From 487dbdb26748b86cf247600af187437310311145 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 1 Nov 2017 13:16:16 +1100 Subject: [PATCH 001/828] py/compile: Use alloca instead of qstr_build when compiling import name. The technique of using alloca is how dotted import names are composed in mp_import_from and mp_builtin___import__, so use the same technique in the compiler. This puts less pressure on the heap (only the stack is used if the qstr already exists, and if it doesn't exist then the standard qstr block memory is used for the new qstr rather than a separate chunk of the heap) and reduces overall code size. --- py/compile.c | 6 +++--- py/qstr.c | 23 ----------------------- py/qstr.h | 3 --- 3 files changed, 3 insertions(+), 29 deletions(-) diff --git a/py/compile.c b/py/compile.c index 4e704abfbb..ee017498ac 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1050,8 +1050,8 @@ STATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) { for (int i = 0; i < n; i++) { len += qstr_len(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i])); } - byte *q_ptr; - byte *str_dest = qstr_build_start(len, &q_ptr); + char *q_ptr = alloca(len); + char *str_dest = q_ptr; for (int i = 0; i < n; i++) { if (i > 0) { *str_dest++ = '.'; @@ -1061,7 +1061,7 @@ STATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) { memcpy(str_dest, str_src, str_src_len); str_dest += str_src_len; } - qstr q_full = qstr_build_end(q_ptr); + qstr q_full = qstr_from_strn(q_ptr, len); EMIT_ARG(import_name, q_full); if (is_as) { for (int i = 1; i < n; i++) { diff --git a/py/qstr.c b/py/qstr.c index 95c9b6835e..a3c9612c65 100644 --- a/py/qstr.c +++ b/py/qstr.c @@ -243,29 +243,6 @@ qstr qstr_from_strn(const char *str, size_t len) { return q; } -byte *qstr_build_start(size_t len, byte **q_ptr) { - assert(len < (1 << (8 * MICROPY_QSTR_BYTES_IN_LEN))); - *q_ptr = m_new(byte, MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len + 1); - Q_SET_LENGTH(*q_ptr, len); - return Q_GET_DATA(*q_ptr); -} - -qstr qstr_build_end(byte *q_ptr) { - QSTR_ENTER(); - qstr q = qstr_find_strn((const char*)Q_GET_DATA(q_ptr), Q_GET_LENGTH(q_ptr)); - if (q == 0) { - size_t len = Q_GET_LENGTH(q_ptr); - mp_uint_t hash = qstr_compute_hash(Q_GET_DATA(q_ptr), len); - Q_SET_HASH(q_ptr, hash); - q_ptr[MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len] = '\0'; - q = qstr_add(q_ptr); - } else { - m_del(byte, q_ptr, Q_GET_ALLOC(q_ptr)); - } - QSTR_EXIT(); - return q; -} - mp_uint_t qstr_hash(qstr q) { return Q_GET_HASH(find_qstr(q)); } diff --git a/py/qstr.h b/py/qstr.h index e2bdcc351e..63fd0c369f 100644 --- a/py/qstr.h +++ b/py/qstr.h @@ -65,9 +65,6 @@ qstr qstr_find_strn(const char *str, size_t str_len); // returns MP_QSTR_NULL if qstr qstr_from_str(const char *str); qstr qstr_from_strn(const char *str, size_t len); -byte *qstr_build_start(size_t len, byte **q_ptr); -qstr qstr_build_end(byte *q_ptr); - mp_uint_t qstr_hash(qstr q); const char *qstr_str(qstr q); size_t qstr_len(qstr q); From 58c785632fc7c4e16885eeb1440b8272069f5190 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 1 Nov 2017 08:59:42 +0200 Subject: [PATCH 002/828] docs/esp8266/general: TLS limitations: Mention also "ussl" module limitations. --- docs/esp8266/general.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/esp8266/general.rst b/docs/esp8266/general.rst index 96a4545323..01eec5b485 100644 --- a/docs/esp8266/general.rst +++ b/docs/esp8266/general.rst @@ -185,3 +185,11 @@ limitation with usage of TLS on the low-memory devices: time, taking as a reference being able to access https://google.com . The smaller buffer hower means that some sites can't be accessed using it, and it's not possible to stream large amounts of data. + +There are also some not implemented features specifically in MicroPython's +``ussl`` module based on axTLS: + +6. Certificates are not validated (this may make connections susceptible + to man-in-the-middle attacks). +7. There is no support for client certificates (scheduled to be fixed in + 1.9.4 release). From 3a9b15fd79c1d1692d529b2b281e2862e9b31179 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 1 Nov 2017 15:16:01 +0200 Subject: [PATCH 003/828] zephyr/README: "make qemu" was replaced with "make run". --- ports/zephyr/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/zephyr/README.md b/ports/zephyr/README.md index 018b4ce715..6e1ea274be 100644 --- a/ports/zephyr/README.md +++ b/ports/zephyr/README.md @@ -46,7 +46,7 @@ Running To run the resulting firmware in QEMU (for BOARDs like qemu_x86, qemu_cortex_m3): - make qemu + make run With the default configuration, networking is now enabled, so you need to follow instructions in https://wiki.zephyrproject.org/view/Networking-with-Qemu @@ -110,4 +110,4 @@ To make a minimal build: To run a minimal build in QEMU without requiring TAP networking setup run the following after you built image with the previous command: - ./make-minimal BOARD= qemu + ./make-minimal BOARD= run From 0719c936fb036f0dd3107cd8bd262d80f95c3ca7 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 2 Nov 2017 00:14:11 +0200 Subject: [PATCH 004/828] extmod/modussl_axtls: socket_read: Handle EAGAIN. If SSL_EAGAIN is returned (which is a feature of MicroPython's axTLS fork), return EAGAIN. Original axTLS returns SSL_OK both when there's no data to return to user yet and when the underlying stream returns EAGAIN. That's not distinctive enough, for example, original module code works well for blocking stream, but will infinite-loop for non-blocking socket with EAGAIN. But if we fix non-blocking case, blocking calls to .read() will return few None's initially (while axTLS progresses thru handshake). Using SSL_EAGAIN allows to fix non-blocking case without regressing the blocking one. Note that this only handles case of non-blocking reads of application data. Initial handshake and writes still don't support non-blocking mode and must be done in the blocking way. --- extmod/modussl_axtls.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extmod/modussl_axtls.c b/extmod/modussl_axtls.c index 3ad65ebf32..9c5722b128 100644 --- a/extmod/modussl_axtls.c +++ b/extmod/modussl_axtls.c @@ -121,6 +121,9 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc // EOF return 0; } + if (r == SSL_EAGAIN) { + r = MP_EAGAIN; + } *errcode = r; return MP_STREAM_ERROR; } From 1cf6d488b3e6b18b21f13f489ded35a47cf3b37d Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 2 Nov 2017 00:16:03 +0200 Subject: [PATCH 005/828] extmod/modussl_axtls: Typo fix in comment. --- extmod/modussl_axtls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/modussl_axtls.c b/extmod/modussl_axtls.c index 9c5722b128..4d8440a89c 100644 --- a/extmod/modussl_axtls.c +++ b/extmod/modussl_axtls.c @@ -113,7 +113,7 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc mp_int_t r = ssl_read(o->ssl_sock, &o->buf); if (r == SSL_OK) { // SSL_OK from ssl_read() means "everything is ok, but there's - // not user data yet. So, we just keep reading. + // no user data yet". So, we just keep reading. continue; } if (r < 0) { From 1742ab265392bde711f4debcd49a42c586540929 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 2 Nov 2017 00:38:58 +0200 Subject: [PATCH 006/828] docs/esp8266/general: Minor grammar fixes. --- docs/esp8266/general.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/esp8266/general.rst b/docs/esp8266/general.rst index 01eec5b485..08d8b4756a 100644 --- a/docs/esp8266/general.rst +++ b/docs/esp8266/general.rst @@ -6,16 +6,16 @@ ESP8266 is a popular WiFi-enabled System-on-Chip (SoC) by Espressif Systems. Multitude of boards ------------------- -There are a multitude of modules and boards from different sources which carry +There is a multitude of modules and boards from different sources which carry the ESP8266 chip. MicroPython tries to provide a generic port which would run on as many boards/modules as possible, but there may be limitations. Adafruit Feather HUZZAH board is taken as a reference board for the port (for example, testing is performed on it). If you have another board, please make sure you -have datasheet, schematics and other reference materials for your board +have a datasheet, schematics and other reference materials for your board handy to look up various aspects of your board functioning. To make a generic ESP8266 port and support as many boards as possible, -following design and implementation decision were made: +the following design and implementation decision were made: * GPIO pin numbering is based on ESP8266 chip numbering, not some "logical" numbering of a particular board. Please have the manual/pin diagram of your board From ad5a6f591796c2dec6e91e9da147eaa7e9ee72a7 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 4 Nov 2017 00:26:31 +0200 Subject: [PATCH 007/828] docs/ure: Add flags arg to ure.compile(), mention that ure.DEBUG is optional. --- docs/library/ure.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/library/ure.rst b/docs/library/ure.rst index ebae1db5f1..9a5a87fb65 100644 --- a/docs/library/ure.rst +++ b/docs/library/ure.rst @@ -47,7 +47,7 @@ etc. are not supported. Functions --------- -.. function:: compile(regex_str) +.. function:: compile(regex_str, [flags]) Compile regular expression, return `regex ` object. @@ -65,6 +65,7 @@ Functions .. data:: DEBUG Flag value, display debug information about compiled expression. + (Availability depends on `MicroPython port`.) .. _regex: From e766a4af4a336816d42d65c01ee6c3e4cc207b7e Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 5 Nov 2017 00:27:21 +0200 Subject: [PATCH 008/828] esp8266/etshal.h: Make function prototypes compatible with ESP SDK 2.1.0+. In the vendor SDK 2.1.0, some of the functions which previously didn't have prototypes, finally acquired them. Change prototypes on our side to match those in vendor headers, to avoid warnings-as-errors. --- ports/esp8266/etshal.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ports/esp8266/etshal.h b/ports/esp8266/etshal.h index 34787779f9..8d64573119 100644 --- a/ports/esp8266/etshal.h +++ b/ports/esp8266/etshal.h @@ -6,14 +6,14 @@ // see http://esp8266-re.foogod.com/wiki/Random_Number_Generator #define WDEV_HWRNG ((volatile uint32_t*)0x3ff20e44) -void ets_delay_us(); +void ets_delay_us(uint16_t us); void ets_intr_lock(void); void ets_intr_unlock(void); void ets_isr_mask(uint32_t mask); void ets_isr_unmask(uint32_t mask); void ets_isr_attach(int irq_no, void (*handler)(void *), void *arg); void ets_install_putc1(); -void uart_div_modify(); +void uart_div_modify(uint8_t uart, uint32_t divisor); void ets_set_idle_cb(void (*handler)(void *), void *arg); void ets_timer_arm_new(os_timer_t *tim, uint32_t millis, bool repeat, bool is_milli_timer); @@ -33,10 +33,10 @@ void MD5Update(MD5_CTX *context, const void *data, unsigned int len); void MD5Final(unsigned char digest[16], MD5_CTX *context); // These prototypes are for recent SDKs with "malloc tracking" -void *pvPortMalloc(unsigned sz, const char *fname, int line); -void *pvPortZalloc(unsigned sz, const char *fname, int line); -void *pvPortRealloc(void *p, unsigned sz, const char *fname, int line); -void vPortFree(void *p, const char *fname, int line); +void *pvPortMalloc(size_t sz, const char *fname, unsigned line); +void *pvPortZalloc(size_t sz, const char *fname, unsigned line); +void *pvPortRealloc(void *p, unsigned sz, const char *fname, unsigned line); +void vPortFree(void *p, const char *fname, unsigned line); uint32_t SPIRead(uint32_t offset, void *buf, uint32_t len); uint32_t SPIWrite(uint32_t offset, const void *buf, uint32_t len); From 99bf5448bd02f9b97f55025725e7d2d4ba9aced8 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 5 Nov 2017 11:37:05 +0200 Subject: [PATCH 009/828] axtls: Update, exposes AES functions to implement ECB chiper mode. --- lib/axtls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/axtls b/lib/axtls index dac9176cac..43a6e6bd3b 160000 --- a/lib/axtls +++ b/lib/axtls @@ -1 +1 @@ -Subproject commit dac9176cac58cc5e49669a9a4d404a6f6dd7cc10 +Subproject commit 43a6e6bd3bbc03dc501e16b89fba0ef042ed3ea0 From cb910c6a0c5338737e5fb7f6f39be0600eb32b72 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 7 Nov 2017 00:43:21 +0200 Subject: [PATCH 010/828] unix/moduselect: Add .dump() method for debugging. Commented out by default. --- ports/unix/moduselect.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ports/unix/moduselect.c b/ports/unix/moduselect.c index ba1c195ef4..45a5c321cd 100644 --- a/ports/unix/moduselect.c +++ b/ports/unix/moduselect.c @@ -277,12 +277,30 @@ STATIC mp_obj_t poll_iternext(mp_obj_t self_in) { return MP_OBJ_STOP_ITERATION; } +STATIC mp_obj_t poll_dump(mp_obj_t self_in) { + mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in); + + struct pollfd *entries = self->entries; + for (int i = self->len - 1; i >= 0; i--) { + printf("fd: %d ev: %x rev: %x", entries->fd, entries->events, entries->revents); + if (self->obj_map) { + printf(" obj: %p", self->obj_map[entries - self->entries]); + } + printf("\n"); + entries++; + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(poll_dump_obj, poll_dump); + STATIC const mp_rom_map_elem_t poll_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_register), MP_ROM_PTR(&poll_register_obj) }, { MP_ROM_QSTR(MP_QSTR_unregister), MP_ROM_PTR(&poll_unregister_obj) }, { MP_ROM_QSTR(MP_QSTR_modify), MP_ROM_PTR(&poll_modify_obj) }, { MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&poll_poll_obj) }, { MP_ROM_QSTR(MP_QSTR_ipoll), MP_ROM_PTR(&poll_ipoll_obj) }, +// { MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&poll_dump_obj) }, }; STATIC MP_DEFINE_CONST_DICT(poll_locals_dict, poll_locals_dict_table); From b9580b85a86a1bae12e31b9734631243cd781014 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 7 Nov 2017 01:13:19 +0200 Subject: [PATCH 011/828] unix/moduselect: Fix nanbox build after adding .dump() method. --- ports/unix/moduselect.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ports/unix/moduselect.c b/ports/unix/moduselect.c index 45a5c321cd..1ea7dc19a5 100644 --- a/ports/unix/moduselect.c +++ b/ports/unix/moduselect.c @@ -40,6 +40,8 @@ #include "py/mphal.h" #include "fdfile.h" +#define DEBUG 0 + #if MICROPY_PY_SOCKET extern const mp_obj_type_t mp_type_socket; #endif @@ -277,6 +279,7 @@ STATIC mp_obj_t poll_iternext(mp_obj_t self_in) { return MP_OBJ_STOP_ITERATION; } +#if DEBUG STATIC mp_obj_t poll_dump(mp_obj_t self_in) { mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in); @@ -293,6 +296,7 @@ STATIC mp_obj_t poll_dump(mp_obj_t self_in) { return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(poll_dump_obj, poll_dump); +#endif STATIC const mp_rom_map_elem_t poll_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_register), MP_ROM_PTR(&poll_register_obj) }, @@ -300,7 +304,9 @@ STATIC const mp_rom_map_elem_t poll_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_modify), MP_ROM_PTR(&poll_modify_obj) }, { MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&poll_poll_obj) }, { MP_ROM_QSTR(MP_QSTR_ipoll), MP_ROM_PTR(&poll_ipoll_obj) }, -// { MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&poll_dump_obj) }, + #if DEBUG + { MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&poll_dump_obj) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(poll_locals_dict, poll_locals_dict_table); From 5b1b80a8dbceb9be67dfd894cdf2a49a7426fd68 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 8 Nov 2017 00:24:39 +0200 Subject: [PATCH 012/828] docs/ure: Emphasize not supported features more. Plus, additional descriptions/formatting. --- docs/library/ure.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/library/ure.rst b/docs/library/ure.rst index 9a5a87fb65..f54614f048 100644 --- a/docs/library/ure.rst +++ b/docs/library/ure.rst @@ -15,8 +15,9 @@ Supported operators are: ``'.'`` Match any character. -``'[]'`` - Match set of characters. Individual characters and ranges are supported. +``'[...]'`` + Match set of characters. Individual characters and ranges are supported, + including negated sets (e.g. ``[^a-c]``). ``'^'`` @@ -36,12 +37,13 @@ Supported operators are: ``'|'`` -``'()'`` +``'(...)'`` Grouping. Each group is capturing (a substring it captures can be accessed with `match.group()` method). -Counted repetitions (``{m,n}``), more advanced assertions, named groups, -etc. are not supported. +**NOT SUPPORTED**: Counted repetitions (``{m,n}``), more advanced assertions +(``\b``, ``\B``), named groups (``(?P...)``), non-capturing groups +(``(?:...)``), etc. Functions From 1b146e9de97708b70c3ad96022886e2ce44d246d Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 8 Nov 2017 19:45:18 +0200 Subject: [PATCH 013/828] py/mpconfig: Introduce reusable MP_HTOBE32(), etc. macros. Macros to convert big-endian values to host byte order and vice-versa. These were defined in adhoc way for some ports (e.g. esp8266), allow reuse, provide default implementations, while allow ports to override. --- ports/esp8266/posix_helpers.c | 5 ++--- py/mpconfig.h | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/ports/esp8266/posix_helpers.c b/ports/esp8266/posix_helpers.c index 1fc677c5c5..b72c4ff9d6 100644 --- a/ports/esp8266/posix_helpers.c +++ b/ports/esp8266/posix_helpers.c @@ -55,14 +55,13 @@ void *realloc(void *ptr, size_t size) { return p; } -#define PLATFORM_HTONL(_n) ((uint32_t)( (((_n) & 0xff) << 24) | (((_n) & 0xff00) << 8) | (((_n) >> 8) & 0xff00) | (((_n) >> 24) & 0xff) )) #undef htonl #undef ntohl uint32_t ntohl(uint32_t netlong) { - return PLATFORM_HTONL(netlong); + return MP_BE32TOH(netlong); } uint32_t htonl(uint32_t netlong) { - return PLATFORM_HTONL(netlong); + return MP_HTOBE32(netlong); } time_t time(time_t *t) { diff --git a/py/mpconfig.h b/py/mpconfig.h index 6a32ea2a6f..fa1094bfc3 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1293,4 +1293,24 @@ typedef double mp_float_t; #define MP_UNLIKELY(x) __builtin_expect((x), 0) #endif +#ifndef MP_HTOBE16 +#if MP_ENDIANNESS_LITTLE +# define MP_HTOBE16(x) ((uint16_t)( (((x) & 0xff) << 8) | (((x) >> 8) & 0xff) )) +# define MP_BE16TOH(x) MP_HTOBE16(x) +#else +# define MP_HTOBE16(x) (x) +# define MP_BE16TOH(x) (x) +#endif +#endif + +#ifndef MP_HTOBE32 +#if MP_ENDIANNESS_LITTLE +# define MP_HTOBE32(x) ((uint32_t)( (((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) >> 8) & 0xff00) | (((x) >> 24) & 0xff) )) +# define MP_BE32TOH(x) MP_HTOBE32(x) +#else +# define MP_HTOBE32(x) (x) +# define MP_BE32TOH(x) (x) +#endif +#endif + #endif // MICROPY_INCLUDED_PY_MPCONFIG_H From 579b86451dba202d573c4c22790ebe3d8ddac060 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 10 Nov 2017 00:09:43 +0200 Subject: [PATCH 014/828] docs/_thread: Add a placeholder docs for _thread module. Doesn't list specific API calls yet, the purpose is to let user know that the module exists. --- docs/library/_thread.rst | 12 ++++++++++++ docs/library/index.rst | 2 ++ 2 files changed, 14 insertions(+) create mode 100644 docs/library/_thread.rst diff --git a/docs/library/_thread.rst b/docs/library/_thread.rst new file mode 100644 index 0000000000..47c1c2392d --- /dev/null +++ b/docs/library/_thread.rst @@ -0,0 +1,12 @@ +:mod:`_thread` -- multithreading support +======================================== + +.. module:: _thread + :synopsis: multithreading support + +|see_cpython_module| :mod:`python:_thread`. + +This module implements multithreading support. + +This module is highly experimental and its API is not yet fully settled +and not yet described in this documentation. diff --git a/docs/library/index.rst b/docs/library/index.rst index 0789ea43d9..b141abf1e6 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -88,6 +88,7 @@ it will fallback to loading the built-in ``ujson`` module. ustruct.rst utime.rst uzlib.rst + _thread.rst .. only:: port_pyboard @@ -114,6 +115,7 @@ it will fallback to loading the built-in ``ujson`` module. ustruct.rst utime.rst uzlib.rst + _thread.rst .. only:: port_wipy From cada971113e6db0cf9e0751e95dbe9217dd707b5 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 11 Nov 2017 00:11:24 +0200 Subject: [PATCH 015/828] py/objtype: mp_obj_new_type: Name base types related vars more clearly. As vars contains array of base types and its length, name them as such, avoid generic "items" and "len" names. --- py/objtype.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/py/objtype.c b/py/objtype.c index 6e2ab6c9a8..a8376a306e 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -983,12 +983,12 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) // TODO might need to make a copy of locals_dict; at least that's how CPython does it // Basic validation of base classes - size_t len; - mp_obj_t *items; - mp_obj_tuple_get(bases_tuple, &len, &items); - for (size_t i = 0; i < len; i++) { - assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type)); - mp_obj_type_t *t = MP_OBJ_TO_PTR(items[i]); + size_t bases_len; + mp_obj_t *bases_items; + mp_obj_tuple_get(bases_tuple, &bases_len, &bases_items); + for (size_t i = 0; i < bases_len; i++) { + assert(MP_OBJ_IS_TYPE(bases_items[i], &mp_type_type)); + mp_obj_type_t *t = MP_OBJ_TO_PTR(bases_items[i]); // TODO: Verify with CPy, tested on function type if (t->make_new == NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { @@ -1014,17 +1014,17 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) //o->iternext = ; not implemented o->buffer_p.get_buffer = instance_get_buffer; - if (len > 0) { + if (bases_len > 0) { // Inherit protocol from a base class. This allows to define an // abstract base class which would translate C-level protocol to // Python method calls, and any subclass inheriting from it will // support this feature. - o->protocol = ((mp_obj_type_t*)MP_OBJ_TO_PTR(items[0]))->protocol; + o->protocol = ((mp_obj_type_t*)MP_OBJ_TO_PTR(bases_items[0]))->protocol; - if (len >= 2) { + if (bases_len >= 2) { o->parent = MP_OBJ_TO_PTR(bases_tuple); } else { - o->parent = MP_OBJ_TO_PTR(items[0]); + o->parent = MP_OBJ_TO_PTR(bases_items[0]); } } From 79ed58f87b008ed1ad75c611686ca8bebfe2a817 Mon Sep 17 00:00:00 2001 From: stijn Date: Mon, 6 Nov 2017 12:21:53 +0100 Subject: [PATCH 016/828] py/objnamedtuple: Add _asdict function if OrderedDict is supported --- ports/unix/mpconfigport_coverage.h | 1 + py/mpconfig.h | 5 +++++ py/objnamedtuple.c | 24 ++++++++++++++++++++++++ tests/basics/namedtuple_asdict.py | 20 ++++++++++++++++++++ 4 files changed, 50 insertions(+) create mode 100644 tests/basics/namedtuple_asdict.py diff --git a/ports/unix/mpconfigport_coverage.h b/ports/unix/mpconfigport_coverage.h index 367b4853af..0dcfdd5fd8 100644 --- a/ports/unix/mpconfigport_coverage.h +++ b/ports/unix/mpconfigport_coverage.h @@ -44,3 +44,4 @@ #undef MICROPY_VFS_FAT #define MICROPY_VFS_FAT (1) #define MICROPY_PY_FRAMEBUF (1) +#define MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT (1) diff --git a/py/mpconfig.h b/py/mpconfig.h index fa1094bfc3..4209b32c6e 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -894,6 +894,11 @@ typedef double mp_float_t; #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (0) #endif +// Whether to provide the _asdict function for namedtuple +#ifndef MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT +#define MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT (0) +#endif + // Whether to provide "math" module #ifndef MICROPY_PY_MATH #define MICROPY_PY_MATH (1) diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index 38daccdf28..94f02dd696 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -52,6 +52,23 @@ STATIC size_t namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr n return (size_t)-1; } +#if MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT +STATIC mp_obj_t namedtuple_asdict(mp_obj_t self_in) { + mp_obj_namedtuple_t *self = MP_OBJ_TO_PTR(self_in); + const qstr *fields = ((mp_obj_namedtuple_type_t*)self->tuple.base.type)->fields; + mp_obj_t dict = mp_obj_new_dict(self->tuple.len); + //make it an OrderedDict + mp_obj_dict_t *dictObj = MP_OBJ_TO_PTR(dict); + dictObj->base.type = &mp_type_ordereddict; + dictObj->map.is_ordered = 1; + for (size_t i = 0; i < self->tuple.len; ++i) { + mp_obj_dict_store(dict, MP_OBJ_NEW_QSTR(fields[i]), self->tuple.items[i]); + } + return dict; +} +MP_DEFINE_CONST_FUN_OBJ_1(namedtuple_asdict_obj, namedtuple_asdict); +#endif + STATIC void namedtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_namedtuple_t *o = MP_OBJ_TO_PTR(o_in); @@ -64,6 +81,13 @@ STATIC void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (dest[0] == MP_OBJ_NULL) { // load attribute mp_obj_namedtuple_t *self = MP_OBJ_TO_PTR(self_in); + #if MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT + if (attr == MP_QSTR__asdict) { + dest[0] = MP_OBJ_FROM_PTR(&namedtuple_asdict_obj); + dest[1] = self_in; + return; + } + #endif size_t id = namedtuple_find_field((mp_obj_namedtuple_type_t*)self->tuple.base.type, attr); if (id == (size_t)-1) { return; diff --git a/tests/basics/namedtuple_asdict.py b/tests/basics/namedtuple_asdict.py new file mode 100644 index 0000000000..c5681376fd --- /dev/null +++ b/tests/basics/namedtuple_asdict.py @@ -0,0 +1,20 @@ +try: + try: + from collections import namedtuple + except ImportError: + from ucollections import namedtuple +except ImportError: + print("SKIP") + raise SystemExit + +t = namedtuple("Tup", ["baz", "foo", "bar"])(3, 2, 5) + +try: + t._asdict +except AttributeError: + print("SKIP") + raise SystemExit + +d = t._asdict() +print(list(d.keys())) +print(list(d.values())) From 9c209e4d09424e6a180276e1fcdddf8f640e8804 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 12 Nov 2017 18:29:27 +0200 Subject: [PATCH 017/828] esp8266/README: Emphasize the need to change default WiFi password. --- ports/esp8266/README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ports/esp8266/README.md b/ports/esp8266/README.md index 252e195d83..04a6039d0b 100644 --- a/ports/esp8266/README.md +++ b/ports/esp8266/README.md @@ -92,12 +92,16 @@ of FlashROM. First start ----------- +Be sure to change ESP8266's WiFi access point password ASAP, see below. + __Serial prompt__ You can access the REPL (Python prompt) over UART (the same as used for programming). - Baudrate: 115200 +Run `help()` for some basic information. + __WiFi__ Initially, the device configures itself as a WiFi access point (AP). @@ -105,14 +109,15 @@ Initially, the device configures itself as a WiFi access point (AP). - Password: micropythoN (note the upper-case N). - IP address of the board: 192.168.4.1. - DHCP-server is activated. +- Please be sure to change the password to something non-guessable + immediately. `help()` gives information how. __WebREPL__ Python prompt over WiFi, connecting through a browser. - Hosted at http://micropython.org/webrepl. - GitHub repository https://github.com/micropython/webrepl. - -Please follow the instructions there. + Please follow the instructions there. Documentation ------------- From 0535d0337042e2c33352aa58ef3f685c0124acab Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 12 Nov 2017 18:34:18 +0200 Subject: [PATCH 018/828] esp8266/README: Add section on using upip. --- ports/esp8266/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/ports/esp8266/README.md b/ports/esp8266/README.md index 04a6039d0b..99e2560162 100644 --- a/ports/esp8266/README.md +++ b/ports/esp8266/README.md @@ -119,6 +119,23 @@ Python prompt over WiFi, connecting through a browser. - GitHub repository https://github.com/micropython/webrepl. Please follow the instructions there. +__upip__ + +The ESP8266 port comes with builtin `upip` package manager, which can +be used to install additional modules (see the main README for more +information): + +``` +>>> import upip +>>> upip.install("micropython-pystone_lowmem") +[...] +>>> import pystone_lowmem +>>> pystone_lowmem.main() +``` + +Downloading and installing packages may requite a lot of free memory, +if you get an error, retry immediately after the hard reset. + Documentation ------------- From 7413b3ce3e344a6a916cd55508dfda8f009df598 Mon Sep 17 00:00:00 2001 From: Christopher Cooper Date: Fri, 10 Nov 2017 21:57:34 +0000 Subject: [PATCH 019/828] extmod/moduhashlib: Enable SHA1 hashing when using "mbedtls" library. The SHA1 hashing functionality is provided via the "axtls" library's implementation, and hence is unavailable when the "axtls" library is not being used. This change provides the same SHA1 hashing functionality when using the "mbedtls" library by using its implementation instead. --- extmod/moduhashlib.c | 55 +++++++++++++++++++++++++++++++++++++++ ports/unix/mpconfigport.h | 2 +- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/extmod/moduhashlib.c b/extmod/moduhashlib.c index 3fad69247e..6469dcfa30 100644 --- a/extmod/moduhashlib.c +++ b/extmod/moduhashlib.c @@ -32,10 +32,19 @@ #if MICROPY_PY_UHASHLIB #include "crypto-algorithms/sha256.h" + #if MICROPY_PY_UHASHLIB_SHA1 + +#if MICROPY_SSL_AXTLS #include "lib/axtls/crypto/crypto.h" #endif +#if MICROPY_SSL_MBEDTLS +#include "mbedtls/sha1.h" +#endif + +#endif + typedef struct _mp_obj_hash_t { mp_obj_base_t base; char state[0]; @@ -57,6 +66,7 @@ STATIC mp_obj_t hash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n #if MICROPY_PY_UHASHLIB_SHA1 STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg); +#if MICROPY_SSL_AXTLS STATIC mp_obj_t sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 0, 1, false); mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(SHA1_CTX)); @@ -69,6 +79,22 @@ STATIC mp_obj_t sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n } #endif +#if MICROPY_SSL_MBEDTLS +STATIC mp_obj_t sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha1_context)); + o->base.type = type; + mbedtls_sha1_init((mbedtls_sha1_context*)o->state); + mbedtls_sha1_starts((mbedtls_sha1_context*)o->state); + if (n_args == 1) { + sha1_update(MP_OBJ_FROM_PTR(o), args[0]); + } + return MP_OBJ_FROM_PTR(o); +} +#endif + +#endif + STATIC mp_obj_t hash_update(mp_obj_t self_in, mp_obj_t arg) { mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_buffer_info_t bufinfo; @@ -79,6 +105,8 @@ STATIC mp_obj_t hash_update(mp_obj_t self_in, mp_obj_t arg) { MP_DEFINE_CONST_FUN_OBJ_2(hash_update_obj, hash_update); #if MICROPY_PY_UHASHLIB_SHA1 + +#if MICROPY_SSL_AXTLS STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg) { mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_buffer_info_t bufinfo; @@ -86,6 +114,18 @@ STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg) { SHA1_Update((SHA1_CTX*)self->state, bufinfo.buf, bufinfo.len); return mp_const_none; } +#endif + +#if MICROPY_SSL_MBEDTLS +STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); + mbedtls_sha1_update((mbedtls_sha1_context*)self->state, bufinfo.buf, bufinfo.len); + return mp_const_none; +} +#endif + MP_DEFINE_CONST_FUN_OBJ_2(sha1_update_obj, sha1_update); #endif @@ -99,6 +139,8 @@ STATIC mp_obj_t hash_digest(mp_obj_t self_in) { MP_DEFINE_CONST_FUN_OBJ_1(hash_digest_obj, hash_digest); #if MICROPY_PY_UHASHLIB_SHA1 + +#if MICROPY_SSL_AXTLS STATIC mp_obj_t sha1_digest(mp_obj_t self_in) { mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); vstr_t vstr; @@ -106,6 +148,19 @@ STATIC mp_obj_t sha1_digest(mp_obj_t self_in) { SHA1_Final((byte*)vstr.buf, (SHA1_CTX*)self->state); return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } +#endif + +#if MICROPY_SSL_MBEDTLS +STATIC mp_obj_t sha1_digest(mp_obj_t self_in) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + vstr_t vstr; + vstr_init_len(&vstr, 20); + mbedtls_sha1_finish((mbedtls_sha1_context*)self->state, (byte*)vstr.buf); + mbedtls_sha1_free((mbedtls_sha1_context*)self->state); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +#endif + MP_DEFINE_CONST_FUN_OBJ_1(sha1_digest_obj, sha1_digest); #endif diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index db382e0a71..a3d2bb7dbd 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -121,7 +121,7 @@ #define MICROPY_PY_UHEAPQ (1) #define MICROPY_PY_UTIMEQ (1) #define MICROPY_PY_UHASHLIB (1) -#if MICROPY_PY_USSL && MICROPY_SSL_AXTLS +#if MICROPY_PY_USSL #define MICROPY_PY_UHASHLIB_SHA1 (1) #endif #define MICROPY_PY_UBINASCII (1) From 964bf935a39498e7224657787b0be277279d2bae Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 14 Nov 2017 09:24:33 +0200 Subject: [PATCH 020/828] esp8266/esp8266_common.ld: Put .text of more libs into .irom0.text . Recent vendor SDKs ship libs with code in .text section, which previously was going into .irom0.text. Adjust the linker script to route these sections back to iROM (follows upstream change). --- ports/esp8266/esp8266_common.ld | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ports/esp8266/esp8266_common.ld b/ports/esp8266/esp8266_common.ld index de5268c8fe..08da02869a 100644 --- a/ports/esp8266/esp8266_common.ld +++ b/ports/esp8266/esp8266_common.ld @@ -73,6 +73,17 @@ SECTIONS _irom0_text_start = ABSOLUTE(.); *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) + /* Vendor SDK in v2.1.0-7-gb8fd588 started to build these with + -ffunction-sections -fdata-sections, and require routing to + irom via linker: + https://github.com/espressif/ESP8266_NONOS_SDK/commit/b8fd588a33f0319dc135523b51655e97b483b205 + */ + + *libcrypto.a:(.literal.* .text.*) + *libnet80211.a:(.literal.* .text.*) + *libwpa.a:(.literal.* .text.*) + *libwpa2.a:(.literal.* .text.*) + /* we put some specific text in this section */ *py/argcheck.o*(.literal* .text*) From 564a95cb040fc425b08a9d3696700364185c3e23 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 15 Nov 2017 11:46:49 +1100 Subject: [PATCH 021/828] py/emitnative: Clean up asm macro names so they have dest as first arg. All the asm macro names that convert a particular architecture to a generic interface now follow the convention whereby the "destination" (usually a register) is specified first. --- py/asmarm.h | 15 +++---- py/asmthumb.h | 15 +++---- py/asmx64.h | 15 +++---- py/asmx86.h | 15 +++---- py/asmxtensa.h | 15 +++---- py/emitnative.c | 105 ++++++++++++++++++++++++++---------------------- 6 files changed, 81 insertions(+), 99 deletions(-) diff --git a/py/asmarm.h b/py/asmarm.h index a302b15905..871e35820b 100644 --- a/py/asmarm.h +++ b/py/asmarm.h @@ -167,17 +167,12 @@ void asm_arm_bl_ind(asm_arm_t *as, void *fun_ptr, uint fun_id, uint reg_temp); } while (0) #define ASM_CALL_IND(as, ptr, idx) asm_arm_bl_ind(as, ptr, idx, ASM_ARM_REG_R3) -#define ASM_MOV_REG_TO_LOCAL(as, reg, local_num) asm_arm_mov_local_reg(as, (local_num), (reg)) -#define ASM_MOV_IMM_TO_REG(as, imm, reg) asm_arm_mov_reg_i32(as, (reg), (imm)) -#define ASM_MOV_ALIGNED_IMM_TO_REG(as, imm, reg) asm_arm_mov_reg_i32(as, (reg), (imm)) -#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \ - do { \ - asm_arm_mov_reg_i32(as, (reg_temp), (imm)); \ - asm_arm_mov_local_reg(as, (local_num), (reg_temp)); \ - } while (false) -#define ASM_MOV_LOCAL_TO_REG(as, local_num, reg) asm_arm_mov_reg_local(as, (reg), (local_num)) +#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_arm_mov_local_reg((as), (local_num), (reg_src)) +#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_arm_mov_reg_i32((as), (reg_dest), (imm)) +#define ASM_MOV_REG_ALIGNED_IMM(as, reg_dest, imm) asm_arm_mov_reg_i32((as), (reg_dest), (imm)) +#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_arm_mov_reg_local((as), (reg_dest), (local_num)) #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_arm_mov_reg_reg((as), (reg_dest), (reg_src)) -#define ASM_MOV_LOCAL_ADDR_TO_REG(as, local_num, reg) asm_arm_mov_reg_local_addr(as, (reg), (local_num)) +#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_arm_mov_reg_local_addr((as), (reg_dest), (local_num)) #define ASM_LSL_REG_REG(as, reg_dest, reg_shift) asm_arm_lsl_reg_reg((as), (reg_dest), (reg_shift)) #define ASM_ASR_REG_REG(as, reg_dest, reg_shift) asm_arm_asr_reg_reg((as), (reg_dest), (reg_shift)) diff --git a/py/asmthumb.h b/py/asmthumb.h index 7070e03ac2..552ad75fca 100644 --- a/py/asmthumb.h +++ b/py/asmthumb.h @@ -283,17 +283,12 @@ void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp } while (0) #define ASM_CALL_IND(as, ptr, idx) asm_thumb_bl_ind(as, ptr, idx, ASM_THUMB_REG_R3) -#define ASM_MOV_REG_TO_LOCAL(as, reg, local_num) asm_thumb_mov_local_reg(as, (local_num), (reg)) -#define ASM_MOV_IMM_TO_REG(as, imm, reg) asm_thumb_mov_reg_i32_optimised(as, (reg), (imm)) -#define ASM_MOV_ALIGNED_IMM_TO_REG(as, imm, reg) asm_thumb_mov_reg_i32_aligned(as, (reg), (imm)) -#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \ - do { \ - asm_thumb_mov_reg_i32_optimised(as, (reg_temp), (imm)); \ - asm_thumb_mov_local_reg(as, (local_num), (reg_temp)); \ - } while (false) -#define ASM_MOV_LOCAL_TO_REG(as, local_num, reg) asm_thumb_mov_reg_local(as, (reg), (local_num)) +#define ASM_MOV_LOCAL_REG(as, local_num, reg) asm_thumb_mov_local_reg((as), (local_num), (reg)) +#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_thumb_mov_reg_i32_optimised((as), (reg_dest), (imm)) +#define ASM_MOV_REG_ALIGNED_IMM(as, reg_dest, imm) asm_thumb_mov_reg_i32_aligned((as), (reg_dest), (imm)) +#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_thumb_mov_reg_local((as), (reg_dest), (local_num)) #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_thumb_mov_reg_reg((as), (reg_dest), (reg_src)) -#define ASM_MOV_LOCAL_ADDR_TO_REG(as, local_num, reg) asm_thumb_mov_reg_local_addr(as, (reg), (local_num)) +#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_thumb_mov_reg_local_addr((as), (reg_dest), (local_num)) #define ASM_LSL_REG_REG(as, reg_dest, reg_shift) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_LSL, (reg_dest), (reg_shift)) #define ASM_ASR_REG_REG(as, reg_dest, reg_shift) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_ASR, (reg_dest), (reg_shift)) diff --git a/py/asmx64.h b/py/asmx64.h index 425bdf2d39..2fbbfa9ffc 100644 --- a/py/asmx64.h +++ b/py/asmx64.h @@ -162,17 +162,12 @@ void asm_x64_call_ind(asm_x64_t* as, void* ptr, int temp_r32); } while (0) #define ASM_CALL_IND(as, ptr, idx) asm_x64_call_ind(as, ptr, ASM_X64_REG_RAX) -#define ASM_MOV_REG_TO_LOCAL asm_x64_mov_r64_to_local -#define ASM_MOV_IMM_TO_REG asm_x64_mov_i64_to_r64_optimised -#define ASM_MOV_ALIGNED_IMM_TO_REG asm_x64_mov_i64_to_r64_aligned -#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \ - do { \ - asm_x64_mov_i64_to_r64_optimised(as, (imm), (reg_temp)); \ - asm_x64_mov_r64_to_local(as, (reg_temp), (local_num)); \ - } while (false) -#define ASM_MOV_LOCAL_TO_REG asm_x64_mov_local_to_r64 +#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_x64_mov_r64_to_local((as), (reg_src), (local_num)) +#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_x64_mov_i64_to_r64_optimised((as), (imm), (reg_dest)) +#define ASM_MOV_REG_ALIGNED_IMM(as, reg_dest, imm) asm_x64_mov_i64_to_r64_aligned((as), (imm), (reg_dest)) +#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_x64_mov_local_to_r64((as), (local_num), (reg_dest)) #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_x64_mov_r64_r64((as), (reg_dest), (reg_src)) -#define ASM_MOV_LOCAL_ADDR_TO_REG asm_x64_mov_local_addr_to_r64 +#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_x64_mov_local_addr_to_r64((as), (local_num), (reg_dest)) #define ASM_LSL_REG(as, reg) asm_x64_shl_r64_cl((as), (reg)) #define ASM_ASR_REG(as, reg) asm_x64_sar_r64_cl((as), (reg)) diff --git a/py/asmx86.h b/py/asmx86.h index 0a00e2e7c2..bd58954531 100644 --- a/py/asmx86.h +++ b/py/asmx86.h @@ -160,17 +160,12 @@ void asm_x86_call_ind(asm_x86_t* as, void* ptr, mp_uint_t n_args, int temp_r32); } while (0) #define ASM_CALL_IND(as, ptr, idx) asm_x86_call_ind(as, ptr, mp_f_n_args[idx], ASM_X86_REG_EAX) -#define ASM_MOV_REG_TO_LOCAL asm_x86_mov_r32_to_local -#define ASM_MOV_IMM_TO_REG asm_x86_mov_i32_to_r32 -#define ASM_MOV_ALIGNED_IMM_TO_REG asm_x86_mov_i32_to_r32_aligned -#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \ - do { \ - asm_x86_mov_i32_to_r32(as, (imm), (reg_temp)); \ - asm_x86_mov_r32_to_local(as, (reg_temp), (local_num)); \ - } while (false) -#define ASM_MOV_LOCAL_TO_REG asm_x86_mov_local_to_r32 +#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_x86_mov_r32_to_local((as), (reg_src), (local_num)) +#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_x86_mov_i32_to_r32((as), (imm), (reg_dest)) +#define ASM_MOV_REG_ALIGNED_IMM(as, reg_dest, imm) asm_x86_mov_i32_to_r32_aligned((as), (imm), (reg_dest)) +#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_x86_mov_local_to_r32((as), (local_num), (reg_dest)) #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_x86_mov_r32_r32((as), (reg_dest), (reg_src)) -#define ASM_MOV_LOCAL_ADDR_TO_REG asm_x86_mov_local_addr_to_r32 +#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_x86_mov_local_addr_to_r32((as), (local_num), (reg_dest)) #define ASM_LSL_REG(as, reg) asm_x86_shl_r32_cl((as), (reg)) #define ASM_ASR_REG(as, reg) asm_x86_sar_r32_cl((as), (reg)) diff --git a/py/asmxtensa.h b/py/asmxtensa.h index 7db6c0d3dc..e6d4158cbc 100644 --- a/py/asmxtensa.h +++ b/py/asmxtensa.h @@ -280,17 +280,12 @@ void asm_xtensa_mov_reg_local_addr(asm_xtensa_t *as, uint reg_dest, int local_nu asm_xtensa_op_callx0(as, ASM_XTENSA_REG_A0); \ } while (0) -#define ASM_MOV_REG_TO_LOCAL(as, reg, local_num) asm_xtensa_mov_local_reg(as, (local_num), (reg)) -#define ASM_MOV_IMM_TO_REG(as, imm, reg) asm_xtensa_mov_reg_i32(as, (reg), (imm)) -#define ASM_MOV_ALIGNED_IMM_TO_REG(as, imm, reg) asm_xtensa_mov_reg_i32(as, (reg), (imm)) -#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \ - do { \ - asm_xtensa_mov_reg_i32(as, (reg_temp), (imm)); \ - asm_xtensa_mov_local_reg(as, (local_num), (reg_temp)); \ - } while (0) -#define ASM_MOV_LOCAL_TO_REG(as, local_num, reg) asm_xtensa_mov_reg_local(as, (reg), (local_num)) +#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_xtensa_mov_local_reg((as), (local_num), (reg_src)) +#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_xtensa_mov_reg_i32((as), (reg_dest), (imm)) +#define ASM_MOV_REG_ALIGNED_IMM(as, reg_dest, imm) asm_xtensa_mov_reg_i32((as), (reg_dest), (imm)) +#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_xtensa_mov_reg_local((as), (reg_dest), (local_num)) #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_mov_n((as), (reg_dest), (reg_src)) -#define ASM_MOV_LOCAL_ADDR_TO_REG(as, local_num, reg) asm_xtensa_mov_reg_local_addr(as, (reg), (local_num)) +#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_xtensa_mov_reg_local_addr((as), (reg_dest), (local_num)) #define ASM_LSL_REG_REG(as, reg_dest, reg_shift) \ do { \ diff --git a/py/emitnative.c b/py/emitnative.c index 8e97dda119..964db95523 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -66,6 +66,13 @@ // this is defined so that the assembler exports generic assembler API macros #define GENERIC_ASM_API (1) +// define additional generic helper macros +#define ASM_MOV_LOCAL_IMM_VIA(as, local_num, imm, reg_temp) \ + do { \ + ASM_MOV_REG_IMM((as), (reg_temp), (imm)); \ + ASM_MOV_LOCAL_REG((as), (local_num), (reg_temp)); \ + } while (false) + #if N_X64 // x64 specific stuff @@ -389,7 +396,7 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3); } else { assert(i == 3); // should be true; max 4 args is checked above - ASM_MOV_REG_TO_LOCAL(emit->as, REG_ARG_4, i - REG_LOCAL_NUM); + ASM_MOV_LOCAL_REG(emit->as, i - REG_LOCAL_NUM, REG_ARG_4); } } #endif @@ -418,14 +425,14 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop #endif // set code_state.fun_bc - ASM_MOV_REG_TO_LOCAL(emit->as, REG_ARG_1, offsetof(mp_code_state_t, fun_bc) / sizeof(uintptr_t)); + ASM_MOV_LOCAL_REG(emit->as, offsetof(mp_code_state_t, fun_bc) / sizeof(uintptr_t), REG_ARG_1); // set code_state.ip (offset from start of this function to prelude info) // XXX this encoding may change size - ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->prelude_offset, offsetof(mp_code_state_t, ip) / sizeof(uintptr_t), REG_ARG_1); + ASM_MOV_LOCAL_IMM_VIA(emit->as, offsetof(mp_code_state_t, ip) / sizeof(uintptr_t), emit->prelude_offset, REG_ARG_1); // put address of code_state into first arg - ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, 0, REG_ARG_1); + ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 0); // call mp_setup_code_state to prepare code_state structure #if N_THUMB @@ -438,11 +445,11 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop // cache some locals in registers if (scope->num_locals > 0) { - ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 0, REG_LOCAL_1); + ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_1, STATE_START + emit->n_state - 1 - 0); if (scope->num_locals > 1) { - ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 1, REG_LOCAL_2); + ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_2, STATE_START + emit->n_state - 1 - 1); if (scope->num_locals > 2) { - ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 2, REG_LOCAL_3); + ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_3, STATE_START + emit->n_state - 1 - 2); } } } @@ -606,7 +613,7 @@ STATIC void need_reg_single(emit_t *emit, int reg_needed, int skip_stack_pos) { stack_info_t *si = &emit->stack_info[i]; if (si->kind == STACK_REG && si->data.u_reg == reg_needed) { si->kind = STACK_VALUE; - ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i); + ASM_MOV_LOCAL_REG(emit->as, emit->stack_start + i, si->data.u_reg); } } } @@ -617,7 +624,7 @@ STATIC void need_reg_all(emit_t *emit) { stack_info_t *si = &emit->stack_info[i]; if (si->kind == STACK_REG) { si->kind = STACK_VALUE; - ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i); + ASM_MOV_LOCAL_REG(emit->as, emit->stack_start + i, si->data.u_reg); } } } @@ -629,7 +636,7 @@ STATIC void need_stack_settled(emit_t *emit) { if (si->kind == STACK_REG) { DEBUG_printf(" reg(%u) to local(%u)\n", si->data.u_reg, emit->stack_start + i); si->kind = STACK_VALUE; - ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i); + ASM_MOV_LOCAL_REG(emit->as, emit->stack_start + i, si->data.u_reg); } } for (int i = 0; i < emit->stack_size; i++) { @@ -637,7 +644,7 @@ STATIC void need_stack_settled(emit_t *emit) { if (si->kind == STACK_IMM) { DEBUG_printf(" imm(" INT_FMT ") to local(%u)\n", si->data.u_imm, emit->stack_start + i); si->kind = STACK_VALUE; - ASM_MOV_IMM_TO_LOCAL_USING(emit->as, si->data.u_imm, emit->stack_start + i, REG_TEMP0); + ASM_MOV_LOCAL_IMM_VIA(emit->as, emit->stack_start + i, si->data.u_imm, REG_TEMP0); } } } @@ -649,7 +656,7 @@ STATIC void emit_access_stack(emit_t *emit, int pos, vtype_kind_t *vtype, int re *vtype = si->vtype; switch (si->kind) { case STACK_VALUE: - ASM_MOV_LOCAL_TO_REG(emit->as, emit->stack_start + emit->stack_size - pos, reg_dest); + ASM_MOV_REG_LOCAL(emit->as, reg_dest, emit->stack_start + emit->stack_size - pos); break; case STACK_REG: @@ -659,7 +666,7 @@ STATIC void emit_access_stack(emit_t *emit, int pos, vtype_kind_t *vtype, int re break; case STACK_IMM: - ASM_MOV_IMM_TO_REG(emit->as, si->data.u_imm, reg_dest); + ASM_MOV_REG_IMM(emit->as, reg_dest, si->data.u_imm); break; } } @@ -671,7 +678,7 @@ STATIC void emit_fold_stack_top(emit_t *emit, int reg_dest) { si[0] = si[1]; if (si->kind == STACK_VALUE) { // if folded element was on the stack we need to put it in a register - ASM_MOV_LOCAL_TO_REG(emit->as, emit->stack_start + emit->stack_size - 1, reg_dest); + ASM_MOV_REG_LOCAL(emit->as, reg_dest, emit->stack_start + emit->stack_size - 1); si->kind = STACK_REG; si->data.u_reg = reg_dest; } @@ -765,30 +772,30 @@ STATIC void emit_call(emit_t *emit, mp_fun_kind_t fun_kind) { STATIC void emit_call_with_imm_arg(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val, int arg_reg) { need_reg_all(emit); - ASM_MOV_IMM_TO_REG(emit->as, arg_val, arg_reg); + ASM_MOV_REG_IMM(emit->as, arg_reg, arg_val); ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind); } // the first arg is stored in the code aligned on a mp_uint_t boundary STATIC void emit_call_with_imm_arg_aligned(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val, int arg_reg) { need_reg_all(emit); - ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, arg_val, arg_reg); + ASM_MOV_REG_ALIGNED_IMM(emit->as, arg_reg, arg_val); ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind); } STATIC void emit_call_with_2_imm_args(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val1, int arg_reg1, mp_int_t arg_val2, int arg_reg2) { need_reg_all(emit); - ASM_MOV_IMM_TO_REG(emit->as, arg_val1, arg_reg1); - ASM_MOV_IMM_TO_REG(emit->as, arg_val2, arg_reg2); + ASM_MOV_REG_IMM(emit->as, arg_reg1, arg_val1); + ASM_MOV_REG_IMM(emit->as, arg_reg2, arg_val2); ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind); } // the first arg is stored in the code aligned on a mp_uint_t boundary STATIC void emit_call_with_3_imm_args_and_first_aligned(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val1, int arg_reg1, mp_int_t arg_val2, int arg_reg2, mp_int_t arg_val3, int arg_reg3) { need_reg_all(emit); - ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, arg_val1, arg_reg1); - ASM_MOV_IMM_TO_REG(emit->as, arg_val2, arg_reg2); - ASM_MOV_IMM_TO_REG(emit->as, arg_val3, arg_reg3); + ASM_MOV_REG_ALIGNED_IMM(emit->as, arg_reg1, arg_val1); + ASM_MOV_REG_IMM(emit->as, arg_reg2, arg_val2); + ASM_MOV_REG_IMM(emit->as, arg_reg3, arg_val3); ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind); } @@ -808,19 +815,19 @@ STATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_de si->kind = STACK_VALUE; switch (si->vtype) { case VTYPE_PYOBJ: - ASM_MOV_IMM_TO_LOCAL_USING(emit->as, si->data.u_imm, emit->stack_start + emit->stack_size - 1 - i, reg_dest); + ASM_MOV_LOCAL_IMM_VIA(emit->as, emit->stack_start + emit->stack_size - 1 - i, si->data.u_imm, reg_dest); break; case VTYPE_BOOL: if (si->data.u_imm == 0) { - ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (mp_uint_t)mp_const_false, emit->stack_start + emit->stack_size - 1 - i, reg_dest); + ASM_MOV_LOCAL_IMM_VIA(emit->as, emit->stack_start + emit->stack_size - 1 - i, (mp_uint_t)mp_const_false, reg_dest); } else { - ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (mp_uint_t)mp_const_true, emit->stack_start + emit->stack_size - 1 - i, reg_dest); + ASM_MOV_LOCAL_IMM_VIA(emit->as, emit->stack_start + emit->stack_size - 1 - i, (mp_uint_t)mp_const_true, reg_dest); } si->vtype = VTYPE_PYOBJ; break; case VTYPE_INT: case VTYPE_UINT: - ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (uintptr_t)MP_OBJ_NEW_SMALL_INT(si->data.u_imm), emit->stack_start + emit->stack_size - 1 - i, reg_dest); + ASM_MOV_LOCAL_IMM_VIA(emit->as, emit->stack_start + emit->stack_size - 1 - i, (uintptr_t)MP_OBJ_NEW_SMALL_INT(si->data.u_imm), reg_dest); si->vtype = VTYPE_PYOBJ; break; default: @@ -838,9 +845,9 @@ STATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_de stack_info_t *si = &emit->stack_info[emit->stack_size - 1 - i]; if (si->vtype != VTYPE_PYOBJ) { mp_uint_t local_num = emit->stack_start + emit->stack_size - 1 - i; - ASM_MOV_LOCAL_TO_REG(emit->as, local_num, REG_ARG_1); + ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, local_num); emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, si->vtype, REG_ARG_2); // arg2 = type - ASM_MOV_REG_TO_LOCAL(emit->as, REG_RET, local_num); + ASM_MOV_LOCAL_REG(emit->as, local_num, REG_RET); si->vtype = VTYPE_PYOBJ; DEBUG_printf(" convert_native_to_obj(local_num=" UINT_FMT ")\n", local_num); } @@ -848,7 +855,7 @@ STATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_de // Adujust the stack for a pop of n_pop items, and load the stack pointer into reg_dest. adjust_stack(emit, -n_pop); - ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, emit->stack_start + emit->stack_size, reg_dest); + ASM_MOV_REG_LOCAL_ADDR(emit->as, reg_dest, emit->stack_start + emit->stack_size); } // vtype of all n_push objects is VTYPE_PYOBJ @@ -858,7 +865,7 @@ STATIC void emit_get_stack_pointer_to_reg_for_push(emit_t *emit, mp_uint_t reg_d emit->stack_info[emit->stack_size + i].kind = STACK_VALUE; emit->stack_info[emit->stack_size + i].vtype = VTYPE_PYOBJ; } - ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, emit->stack_start + emit->stack_size, reg_dest); + ASM_MOV_REG_LOCAL_ADDR(emit->as, reg_dest, emit->stack_start + emit->stack_size); adjust_stack(emit, n_push); } @@ -881,7 +888,7 @@ STATIC void emit_native_import_name(emit_t *emit, qstr qst) { stack_info_t *top = peek_stack(emit, 0); if (top->vtype == VTYPE_PTR_NONE) { emit_pre_pop_discard(emit); - ASM_MOV_IMM_TO_REG(emit->as, (mp_uint_t)mp_const_none, REG_ARG_2); + ASM_MOV_REG_IMM(emit->as, REG_ARG_2, (mp_uint_t)mp_const_none); } else { vtype_kind_t vtype_fromlist; emit_pre_pop_reg(emit, &vtype_fromlist, REG_ARG_2); @@ -891,7 +898,7 @@ STATIC void emit_native_import_name(emit_t *emit, qstr qst) { // level argument should be an immediate integer top = peek_stack(emit, 0); assert(top->vtype == VTYPE_INT && top->kind == STACK_IMM); - ASM_MOV_IMM_TO_REG(emit->as, (mp_uint_t)MP_OBJ_NEW_SMALL_INT(top->data.u_imm), REG_ARG_3); + ASM_MOV_REG_IMM(emit->as, REG_ARG_3, (mp_uint_t)MP_OBJ_NEW_SMALL_INT(top->data.u_imm)); emit_pre_pop_discard(emit); } else { @@ -981,7 +988,7 @@ STATIC void emit_native_load_const_str(emit_t *emit, qstr qst) { STATIC void emit_native_load_const_obj(emit_t *emit, mp_obj_t obj) { emit_native_pre(emit); need_reg_single(emit, REG_RET, 0); - ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, (mp_uint_t)obj, REG_RET); + ASM_MOV_REG_ALIGNED_IMM(emit->as, REG_RET, (mp_uint_t)obj); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } @@ -1006,9 +1013,9 @@ STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { } else { need_reg_single(emit, REG_TEMP0, 0); if (emit->do_viper_types) { - ASM_MOV_LOCAL_TO_REG(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0); + ASM_MOV_REG_LOCAL(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM); } else { - ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - local_num, REG_TEMP0); + ASM_MOV_REG_LOCAL(emit->as, REG_TEMP0, STATE_START + emit->n_state - 1 - local_num); } emit_post_push_reg(emit, vtype, REG_TEMP0); } @@ -1134,7 +1141,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) { break; } #endif - ASM_MOV_IMM_TO_REG(emit->as, index_value, reg_index); + ASM_MOV_REG_IMM(emit->as, reg_index, index_value); ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add index to base reg_base = reg_index; } @@ -1151,7 +1158,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) { break; } #endif - ASM_MOV_IMM_TO_REG(emit->as, index_value << 1, reg_index); + ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 1); ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 2*index to base reg_base = reg_index; } @@ -1168,7 +1175,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) { break; } #endif - ASM_MOV_IMM_TO_REG(emit->as, index_value << 2, reg_index); + ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 2); ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 4*index to base reg_base = reg_index; } @@ -1233,9 +1240,9 @@ STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) } else { emit_pre_pop_reg(emit, &vtype, REG_TEMP0); if (emit->do_viper_types) { - ASM_MOV_REG_TO_LOCAL(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM); + ASM_MOV_LOCAL_REG(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0); } else { - ASM_MOV_REG_TO_LOCAL(emit->as, REG_TEMP0, STATE_START + emit->n_state - 1 - local_num); + ASM_MOV_LOCAL_REG(emit->as, STATE_START + emit->n_state - 1 - local_num, REG_TEMP0); } } emit_post(emit); @@ -1354,7 +1361,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) { break; } #endif - ASM_MOV_IMM_TO_REG(emit->as, index_value, reg_index); + ASM_MOV_REG_IMM(emit->as, reg_index, index_value); #if N_ARM asm_arm_strb_reg_reg_reg(emit->as, reg_value, reg_base, reg_index); return; @@ -1375,7 +1382,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) { break; } #endif - ASM_MOV_IMM_TO_REG(emit->as, index_value << 1, reg_index); + ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 1); #if N_ARM asm_arm_strh_reg_reg_reg(emit->as, reg_value, reg_base, reg_index); return; @@ -1396,7 +1403,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) { break; } #endif - ASM_MOV_IMM_TO_REG(emit->as, index_value << 2, reg_index); + ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 2); #if N_ARM asm_arm_str_reg_reg_reg(emit->as, reg_value, reg_base, reg_index); return; @@ -1773,7 +1780,7 @@ STATIC void emit_native_get_iter(emit_t *emit, bool use_stack) { emit_call(emit, MP_F_NATIVE_GETITER); } else { // mp_getiter will allocate the iter_buf on the heap - ASM_MOV_IMM_TO_REG(emit->as, 0, REG_ARG_2); + ASM_MOV_REG_IMM(emit->as, REG_ARG_2, 0); emit_call(emit, MP_F_NATIVE_GETITER); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } @@ -1784,7 +1791,7 @@ STATIC void emit_native_for_iter(emit_t *emit, mp_uint_t label) { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_1, MP_OBJ_ITER_BUF_NSLOTS); adjust_stack(emit, MP_OBJ_ITER_BUF_NSLOTS); emit_call(emit, MP_F_NATIVE_ITERNEXT); - ASM_MOV_IMM_TO_REG(emit->as, (mp_uint_t)MP_OBJ_STOP_ITERATION, REG_TEMP1); + ASM_MOV_REG_IMM(emit->as, REG_TEMP1, (mp_uint_t)MP_OBJ_STOP_ITERATION); ASM_JUMP_IF_REG_EQ(emit->as, REG_RET, REG_TEMP1, label); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } @@ -2128,12 +2135,12 @@ STATIC void emit_native_make_closure(emit_t *emit, scope_t *scope, mp_uint_t n_c emit_native_pre(emit); if (n_pos_defaults == 0 && n_kw_defaults == 0) { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_closed_over); - ASM_MOV_IMM_TO_REG(emit->as, n_closed_over, REG_ARG_2); + ASM_MOV_REG_IMM(emit->as, REG_ARG_2, n_closed_over); } else { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_closed_over + 2); - ASM_MOV_IMM_TO_REG(emit->as, 0x100 | n_closed_over, REG_ARG_2); + ASM_MOV_REG_IMM(emit->as, REG_ARG_2, 0x100 | n_closed_over); } - ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, (mp_uint_t)scope->raw_code, REG_ARG_1); + ASM_MOV_REG_ALIGNED_IMM(emit->as, REG_ARG_1, (mp_uint_t)scope->raw_code); ASM_CALL_IND(emit->as, mp_fun_table[MP_F_MAKE_CLOSURE_FROM_RAW_CODE], MP_F_MAKE_CLOSURE_FROM_RAW_CODE); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } @@ -2212,9 +2219,9 @@ STATIC void emit_native_return_value(emit_t *emit) { if (peek_vtype(emit, 0) == VTYPE_PTR_NONE) { emit_pre_pop_discard(emit); if (emit->return_vtype == VTYPE_PYOBJ) { - ASM_MOV_IMM_TO_REG(emit->as, (mp_uint_t)mp_const_none, REG_RET); + ASM_MOV_REG_IMM(emit->as, REG_RET, (mp_uint_t)mp_const_none); } else { - ASM_MOV_IMM_TO_REG(emit->as, 0, REG_RET); + ASM_MOV_REG_IMM(emit->as, REG_RET, 0); } } else { vtype_kind_t vtype; From 1871a924c97cec16d0670d136e9f7056f99865df Mon Sep 17 00:00:00 2001 From: Christopher Arndt Date: Tue, 31 Oct 2017 17:19:12 +0100 Subject: [PATCH 022/828] py/mkenv.mk: Use $(PYTHON) consistently when calling Python tools. Rationale: * Calling Python build tool scripts from makefiles should be done consistently using `python `, instead of relying on the correct she-bang line in the script [1] and the executable bit on the script being set. This is more platform-independent. * The name/path of the Python executable should always be used via the makefile variable `PYTHON` set in `py/mkenv.mk`. This way it can be easily overwritten by the user with `make PYTHON=/path/to/my/python`. * The Python executable name should be part of the value of the makefile variable, which stands for the build tool command (e.g. `MAKE_FROZEN` and `MPY_TOOL`), not part of the command line where it is used. If a Python tool is substituted by another (non-python) program, no change to the Makefiles is necessary, except in `py/mkenv.mk`. * This also solves #3369 and #1616. [1] There are systems, where even the assumption that `/usr/bin/env` always exists, doesn't hold true, for example on Android (where otherwise the unix port compiles perfectly well). --- py/mkenv.mk | 4 ++-- py/mkrules.mk | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/py/mkenv.mk b/py/mkenv.mk index b167b2533d..2c9c86a7ae 100644 --- a/py/mkenv.mk +++ b/py/mkenv.mk @@ -58,9 +58,9 @@ CXX += -m32 LD += -m32 endif -MAKE_FROZEN = $(TOP)/tools/make-frozen.py +MAKE_FROZEN = $(PYTHON) $(TOP)/tools/make-frozen.py MPY_CROSS = $(TOP)/mpy-cross/mpy-cross -MPY_TOOL = $(TOP)/tools/mpy-tool.py +MPY_TOOL = $(PYTHON) $(TOP)/tools/mpy-tool.py all: .PHONY: all diff --git a/py/mkrules.mk b/py/mkrules.mk index 13545eb6f0..72a5c3de06 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -119,7 +119,7 @@ $(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/%.py $(TOP)/mpy-cross/mpy-cross # to build frozen_mpy.c from all .mpy files $(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h @$(ECHO) "Creating $@" - $(Q)$(PYTHON) $(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@ + $(Q)$(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@ endif ifneq ($(PROG),) From 2cafef857e357bbfcf3bb3c6d10e62b778642695 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 15 Nov 2017 12:23:29 +1100 Subject: [PATCH 023/828] stm32/boards/NUCLEO_F429ZI: Incr CPU freq to 168MHz to get USB working. At the original frequency of 90MHz there's no way to get a 48MHz USB clock. These new setting mirror those of the STM32F429DISC board. --- ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h index 42cc9d68cd..608beef672 100644 --- a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h @@ -16,9 +16,9 @@ // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) -#define MICROPY_HW_CLK_PLLN (180) +#define MICROPY_HW_CLK_PLLN (336) #define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) -#define MICROPY_HW_CLK_PLLQ (4) +#define MICROPY_HW_CLK_PLLQ (7) // From the reference manual, for 2.7V to 3.6V // 151-180 MHz => 5 wait states From 9ba3de6ea19a7c86f7ecd9ceefabbf732949e662 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 15 Nov 2017 12:46:08 +1100 Subject: [PATCH 024/828] tools/mpy-tool.py: Implement freezing of Ellipsis const object. --- tools/mpy-tool.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index ac7b2c1ccf..eeb760a5f6 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -287,7 +287,9 @@ class RawCode: # generate constant objects for i, obj in enumerate(self.objs): obj_name = 'const_obj_%s_%u' % (self.escaped_name, i) - if is_str_type(obj) or is_bytes_type(obj): + if obj is Ellipsis: + print('#define %s mp_const_ellipsis_obj' % obj_name) + elif is_str_type(obj) or is_bytes_type(obj): if is_str_type(obj): obj = bytes_cons(obj, 'utf8') obj_type = 'mp_type_str' @@ -328,7 +330,6 @@ class RawCode: print('STATIC const mp_obj_complex_t %s = {{&mp_type_complex}, %.16g, %.16g};' % (obj_name, obj.real, obj.imag)) else: - # TODO raise FreezeError(self, 'freezing of object %r is not implemented' % (obj,)) # generate constant table, if it has any entries From 6bc55b657b900dd92ebb8b4a8c393644a30dd7e6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 16 Nov 2017 13:13:24 +1100 Subject: [PATCH 025/828] extmod/vfs: Use existing qstr for forward-slash string object. --- extmod/vfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extmod/vfs.c b/extmod/vfs.c index 44ad8ffad6..105a80a8df 100644 --- a/extmod/vfs.c +++ b/extmod/vfs.c @@ -261,7 +261,7 @@ mp_obj_t mp_vfs_chdir(mp_obj_t path_in) { // subsequent relative paths begin at the root of that VFS. for (vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) { if (vfs->len == 1) { - mp_obj_t root = mp_obj_new_str("/", 1, false); + mp_obj_t root = MP_OBJ_NEW_QSTR(MP_QSTR__slash_); mp_vfs_proxy_call(vfs, MP_QSTR_chdir, 1, &root); break; } @@ -318,7 +318,7 @@ STATIC mp_obj_t mp_vfs_ilistdir_it_iternext(mp_obj_t self_in) { self->cur.vfs = vfs->next; if (vfs->len == 1) { // vfs is mounted at root dir, delegate to it - mp_obj_t root = mp_obj_new_str("/", 1, false); + mp_obj_t root = MP_OBJ_NEW_QSTR(MP_QSTR__slash_); self->is_iter = true; self->cur.iter = mp_vfs_proxy_call(vfs, MP_QSTR_ilistdir, 1, &root); return mp_iternext(self->cur.iter); From 4601759bf59e16b860a3f082e9aa4ea78356bf92 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 16 Nov 2017 13:17:51 +1100 Subject: [PATCH 026/828] py/objstr: Remove "make_qstr_if_not_already" arg from mp_obj_new_str. This patch simplifies the str creation API to favour the common case of creating a str object that is not forced to be interned. To force interning of a new str the new mp_obj_new_str_via_qstr function is added, and should only be used if warranted. Apart from simplifying the mp_obj_new_str function (and making it have the same signature as mp_obj_new_bytes), this patch also reduces code size by a bit (-16 bytes for bare-arm and roughly -40 bytes on the bare-metal archs). --- extmod/modujson.c | 2 +- extmod/modwebrepl.c | 2 +- extmod/vfs_fat.c | 2 +- extmod/vfs_fat_misc.c | 2 +- extmod/vfs_reader.c | 2 +- lib/netutils/netutils.c | 2 +- ports/cc3200/mods/modwlan.c | 10 +++++----- ports/esp8266/modnetwork.c | 4 ++-- ports/esp8266/moduos.c | 2 +- ports/stm32/modnwcc3k.c | 4 ++-- ports/unix/coverage.c | 6 +++--- ports/unix/main.c | 6 +++--- ports/unix/modffi.c | 2 +- ports/unix/modjni.c | 2 +- ports/unix/modos.c | 4 ++-- ports/zephyr/modusocket.c | 2 +- py/binary.c | 2 +- py/builtinhelp.c | 2 +- py/builtinimport.c | 2 +- py/modbuiltins.c | 4 ++-- py/modio.c | 2 +- py/obj.h | 3 ++- py/objstr.c | 36 ++++++++++++++++++------------------ py/objstrunicode.c | 4 ++-- 24 files changed, 55 insertions(+), 54 deletions(-) diff --git a/extmod/modujson.c b/extmod/modujson.c index f14682d26f..6eeba4ed60 100644 --- a/extmod/modujson.c +++ b/extmod/modujson.c @@ -166,7 +166,7 @@ STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) { goto fail; } S_NEXT(s); - next = mp_obj_new_str(vstr.buf, vstr.len, false); + next = mp_obj_new_str(vstr.buf, vstr.len); break; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c index 3aba5c0f10..42b30f5ea4 100644 --- a/extmod/modwebrepl.c +++ b/extmod/modwebrepl.c @@ -141,7 +141,7 @@ STATIC void handle_op(mp_obj_webrepl_t *self) { // Handle operations requiring opened file mp_obj_t open_args[2] = { - mp_obj_new_str(self->hdr.fname, strlen(self->hdr.fname), false), + mp_obj_new_str(self->hdr.fname, strlen(self->hdr.fname)), MP_OBJ_NEW_QSTR(MP_QSTR_rb) }; diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 22346bdf1d..9942ddeb55 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -197,7 +197,7 @@ STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) { if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); } - return mp_obj_new_str(buf, strlen(buf), false); + return mp_obj_new_str(buf, strlen(buf)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getcwd_obj, fat_vfs_getcwd); diff --git a/extmod/vfs_fat_misc.c b/extmod/vfs_fat_misc.c index 9a26b4a2f9..1f90ac14ce 100644 --- a/extmod/vfs_fat_misc.c +++ b/extmod/vfs_fat_misc.c @@ -57,7 +57,7 @@ STATIC mp_obj_t mp_vfs_fat_ilistdir_it_iternext(mp_obj_t self_in) { // make 3-tuple with info about this entry mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); if (self->is_str) { - t->items[0] = mp_obj_new_str(fn, strlen(fn), false); + t->items[0] = mp_obj_new_str(fn, strlen(fn)); } else { t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn)); } diff --git a/extmod/vfs_reader.c b/extmod/vfs_reader.c index 891098aa1e..e1ee45a3c7 100644 --- a/extmod/vfs_reader.c +++ b/extmod/vfs_reader.c @@ -71,7 +71,7 @@ STATIC void mp_reader_vfs_close(void *data) { void mp_reader_new_file(mp_reader_t *reader, const char *filename) { mp_reader_vfs_t *rf = m_new_obj(mp_reader_vfs_t); - mp_obj_t arg = mp_obj_new_str(filename, strlen(filename), false); + mp_obj_t arg = mp_obj_new_str(filename, strlen(filename)); rf->file = mp_vfs_open(1, &arg, (mp_map_t*)&mp_const_empty_map); int errcode; rf->len = mp_stream_rw(rf->file, rf->buf, sizeof(rf->buf), &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); diff --git a/lib/netutils/netutils.c b/lib/netutils/netutils.c index 06c3ff9b08..073f46b199 100644 --- a/lib/netutils/netutils.c +++ b/lib/netutils/netutils.c @@ -41,7 +41,7 @@ mp_obj_t netutils_format_ipv4_addr(uint8_t *ip, netutils_endian_t endian) { } else { ip_len = snprintf(ip_str, 16, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); } - return mp_obj_new_str(ip_str, ip_len, false); + return mp_obj_new_str(ip_str, ip_len); } // Takes an array with a raw IP address, and a port, and returns a net-address diff --git a/ports/cc3200/mods/modwlan.c b/ports/cc3200/mods/modwlan.c index f9c7111b38..8acc89da38 100644 --- a/ports/cc3200/mods/modwlan.c +++ b/ports/cc3200/mods/modwlan.c @@ -885,7 +885,7 @@ STATIC mp_obj_t wlan_scan(mp_obj_t self_in) { } mp_obj_t tuple[5]; - tuple[0] = mp_obj_new_str((const char *)wlanEntry.ssid, wlanEntry.ssid_len, false); + tuple[0] = mp_obj_new_str((const char *)wlanEntry.ssid, wlanEntry.ssid_len); tuple[1] = mp_obj_new_bytes((const byte *)wlanEntry.bssid, SL_BSSID_LENGTH); // 'normalize' the security type if (wlanEntry.sec_type > 2) { @@ -1075,7 +1075,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_mode_obj, 1, 2, wlan_mode); STATIC mp_obj_t wlan_ssid(size_t n_args, const mp_obj_t *args) { wlan_obj_t *self = args[0]; if (n_args == 1) { - return mp_obj_new_str((const char *)self->ssid, strlen((const char *)self->ssid), false); + return mp_obj_new_str((const char *)self->ssid, strlen((const char *)self->ssid)); } else { size_t len; const char *ssid = mp_obj_str_get_data(args[1], &len); @@ -1095,7 +1095,7 @@ STATIC mp_obj_t wlan_auth(size_t n_args, const mp_obj_t *args) { } else { mp_obj_t security[2]; security[0] = mp_obj_new_int(self->auth); - security[1] = mp_obj_new_str((const char *)self->key, strlen((const char *)self->key), false); + security[1] = mp_obj_new_str((const char *)self->key, strlen((const char *)self->key)); return mp_obj_new_tuple(2, security); } } else { @@ -1199,7 +1199,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_irq_obj, 1, wlan_irq); // mp_obj_t connections = mp_obj_new_list(0, NULL); // // if (wlan_is_connected()) { -// device[0] = mp_obj_new_str((const char *)wlan_obj.ssid_o, strlen((const char *)wlan_obj.ssid_o), false); +// device[0] = mp_obj_new_str((const char *)wlan_obj.ssid_o, strlen((const char *)wlan_obj.ssid_o)); // device[1] = mp_obj_new_bytes((const byte *)wlan_obj.bssid, SL_BSSID_LENGTH); // // add the device to the list // mp_obj_list_append(connections, mp_obj_new_tuple(MP_ARRAY_SIZE(device), device)); @@ -1232,7 +1232,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_irq_obj, 1, wlan_irq); // if (sl_NetAppGet(SL_NET_APP_DEVICE_CONFIG_ID, NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN, &len, (uint8_t *)urn) < 0) { // mp_raise_OSError(MP_EIO); // } -// return mp_obj_new_str(urn, (len - 1), false); +// return mp_obj_new_str(urn, (len - 1)); // } // // return mp_const_none; diff --git a/ports/esp8266/modnetwork.c b/ports/esp8266/modnetwork.c index b41a11f596..4066c969ce 100644 --- a/ports/esp8266/modnetwork.c +++ b/ports/esp8266/modnetwork.c @@ -411,7 +411,7 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs } case QS(MP_QSTR_essid): req_if = SOFTAP_IF; - val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len, false); + val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len); break; case QS(MP_QSTR_hidden): req_if = SOFTAP_IF; @@ -428,7 +428,7 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs case QS(MP_QSTR_dhcp_hostname): { req_if = STATION_IF; char* s = wifi_station_get_hostname(); - val = mp_obj_new_str(s, strlen(s), false); + val = mp_obj_new_str(s, strlen(s)); break; } default: diff --git a/ports/esp8266/moduos.c b/ports/esp8266/moduos.c index d0554096ed..93f7aa712d 100644 --- a/ports/esp8266/moduos.c +++ b/ports/esp8266/moduos.c @@ -60,7 +60,7 @@ STATIC mp_obj_tuple_t os_uname_info_obj = { STATIC mp_obj_t os_uname(void) { // We must populate the "release" field each time in case it was GC'd since the last call. const char *ver = system_get_sdk_version(); - os_uname_info_obj.items[2] = mp_obj_new_str(ver, strlen(ver), false); + os_uname_info_obj.items[2] = mp_obj_new_str(ver, strlen(ver)); return (mp_obj_t)&os_uname_info_obj; } STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname); diff --git a/ports/stm32/modnwcc3k.c b/ports/stm32/modnwcc3k.c index 8cc0a613d1..4f1af7354c 100644 --- a/ports/stm32/modnwcc3k.c +++ b/ports/stm32/modnwcc3k.c @@ -531,8 +531,8 @@ STATIC mp_obj_t cc3k_ifconfig(mp_obj_t self_in) { netutils_format_ipv4_addr(ipconfig.aucDefaultGateway, NETUTILS_LITTLE), netutils_format_ipv4_addr(ipconfig.aucDNSServer, NETUTILS_LITTLE), netutils_format_ipv4_addr(ipconfig.aucDHCPServer, NETUTILS_LITTLE), - mp_obj_new_str(mac_vstr.buf, mac_vstr.len, false), - mp_obj_new_str((const char*)ipconfig.uaSSID, strlen((const char*)ipconfig.uaSSID), false), + mp_obj_new_str(mac_vstr.buf, mac_vstr.len), + mp_obj_new_str((const char*)ipconfig.uaSSID, strlen((const char*)ipconfig.uaSSID)), }; return mp_obj_new_tuple(MP_ARRAY_SIZE(tuple), tuple); } diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 651db0a943..e2896c2dd1 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -227,7 +227,7 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "# str\n"); // intern string - mp_printf(&mp_plat_print, "%d\n", MP_OBJ_IS_QSTR(mp_obj_str_intern(mp_obj_new_str("intern me", 9, false)))); + mp_printf(&mp_plat_print, "%d\n", MP_OBJ_IS_QSTR(mp_obj_str_intern(mp_obj_new_str("intern me", 9)))); } // mpz @@ -260,12 +260,12 @@ STATIC mp_obj_t extra_coverage(void) { // call mp_call_function_1_protected mp_call_function_1_protected(MP_OBJ_FROM_PTR(&mp_builtin_abs_obj), MP_OBJ_NEW_SMALL_INT(1)); // call mp_call_function_1_protected with invalid args - mp_call_function_1_protected(MP_OBJ_FROM_PTR(&mp_builtin_abs_obj), mp_obj_new_str("abc", 3, false)); + mp_call_function_1_protected(MP_OBJ_FROM_PTR(&mp_builtin_abs_obj), mp_obj_new_str("abc", 3)); // call mp_call_function_2_protected mp_call_function_2_protected(MP_OBJ_FROM_PTR(&mp_builtin_divmod_obj), MP_OBJ_NEW_SMALL_INT(1), MP_OBJ_NEW_SMALL_INT(1)); // call mp_call_function_2_protected with invalid args - mp_call_function_2_protected(MP_OBJ_FROM_PTR(&mp_builtin_divmod_obj), mp_obj_new_str("abc", 3, false), mp_obj_new_str("abc", 3, false)); + mp_call_function_2_protected(MP_OBJ_FROM_PTR(&mp_builtin_divmod_obj), mp_obj_new_str("abc", 3), mp_obj_new_str("abc", 3)); } // warning diff --git a/ports/unix/main.c b/ports/unix/main.c index e1cd33fc1e..25f3e04fb8 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -481,7 +481,7 @@ MP_NOINLINE int main_(int argc, char **argv) { vstr_add_strn(&vstr, p + 1, p1 - p - 1); path_items[i] = mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } else { - path_items[i] = MP_OBJ_NEW_QSTR(qstr_from_strn(p, p1 - p)); + path_items[i] = mp_obj_new_str_via_qstr(p, p1 - p); } p = p1 + 1; } @@ -537,7 +537,7 @@ MP_NOINLINE int main_(int argc, char **argv) { return usage(argv); } mp_obj_t import_args[4]; - import_args[0] = mp_obj_new_str(argv[a + 1], strlen(argv[a + 1]), false); + import_args[0] = mp_obj_new_str(argv[a + 1], strlen(argv[a + 1])); import_args[1] = import_args[2] = mp_const_none; // Ask __import__ to handle imported module specially - set its __name__ // to __main__, and also return this leaf module, not top-level package @@ -603,7 +603,7 @@ MP_NOINLINE int main_(int argc, char **argv) { // Set base dir of the script as first entry in sys.path char *p = strrchr(basedir, '/'); - path_items[0] = MP_OBJ_NEW_QSTR(qstr_from_strn(basedir, p - basedir)); + path_items[0] = mp_obj_new_str_via_qstr(basedir, p - basedir); free(pathbuf); set_sys_argv(argv, argc, a); diff --git a/ports/unix/modffi.c b/ports/unix/modffi.c index 78adccac12..024f83c141 100644 --- a/ports/unix/modffi.c +++ b/ports/unix/modffi.c @@ -144,7 +144,7 @@ STATIC mp_obj_t return_ffi_value(ffi_arg val, char type) if (!s) { return mp_const_none; } - return mp_obj_new_str(s, strlen(s), false); + return mp_obj_new_str(s, strlen(s)); } case 'v': return mp_const_none; diff --git a/ports/unix/modjni.c b/ports/unix/modjni.c index f29c095cf5..8ec5ae54d9 100644 --- a/ports/unix/modjni.c +++ b/ports/unix/modjni.c @@ -337,7 +337,7 @@ STATIC mp_obj_t new_jobject(jobject jo) { return mp_const_none; } else if (JJ(IsInstanceOf, jo, String_class)) { const char *s = JJ(GetStringUTFChars, jo, NULL); - mp_obj_t ret = mp_obj_new_str(s, strlen(s), false); + mp_obj_t ret = mp_obj_new_str(s, strlen(s)); JJ(ReleaseStringUTFChars, jo, s); return ret; } else if (JJ(IsInstanceOf, jo, Class_class)) { diff --git a/ports/unix/modos.c b/ports/unix/modos.c index 327116a0a6..808d12adb8 100644 --- a/ports/unix/modos.c +++ b/ports/unix/modos.c @@ -133,7 +133,7 @@ STATIC mp_obj_t mod_os_getenv(mp_obj_t var_in) { if (s == NULL) { return mp_const_none; } - return mp_obj_new_str(s, strlen(s), false); + return mp_obj_new_str(s, strlen(s)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_getenv_obj, mod_os_getenv); @@ -171,7 +171,7 @@ STATIC mp_obj_t listdir_next(mp_obj_t self_in) { } mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); - t->items[0] = mp_obj_new_str(dirent->d_name, strlen(dirent->d_name), false); + t->items[0] = mp_obj_new_str(dirent->d_name, strlen(dirent->d_name)); #ifdef _DIRENT_HAVE_D_TYPE t->items[1] = MP_OBJ_NEW_SMALL_INT(dirent->d_type); #else diff --git a/ports/zephyr/modusocket.c b/ports/zephyr/modusocket.c index e021c3a44f..95414a49b4 100644 --- a/ports/zephyr/modusocket.c +++ b/ports/zephyr/modusocket.c @@ -91,7 +91,7 @@ STATIC mp_obj_t format_inet_addr(struct sockaddr *addr, mp_obj_t port) { net_addr_ntop(addr->sa_family, &sockaddr_in6->sin6_addr, buf, sizeof(buf)); mp_obj_tuple_t *tuple = mp_obj_new_tuple(addr->sa_family == AF_INET ? 2 : 4, NULL); - tuple->items[0] = mp_obj_new_str(buf, strlen(buf), false); + tuple->items[0] = mp_obj_new_str(buf, strlen(buf)); // We employ the fact that port offset is the same for IPv4 & IPv6 // not filled in //tuple->items[1] = mp_obj_new_int(ntohs(((struct sockaddr_in*)addr)->sin_port)); diff --git a/py/binary.c b/py/binary.c index 870a0942ba..f509ff0108 100644 --- a/py/binary.c +++ b/py/binary.c @@ -206,7 +206,7 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) { return (mp_obj_t)(mp_uint_t)val; } else if (val_type == 'S') { const char *s_val = (const char*)(uintptr_t)(mp_uint_t)val; - return mp_obj_new_str(s_val, strlen(s_val), false); + return mp_obj_new_str(s_val, strlen(s_val)); #if MICROPY_PY_BUILTINS_FLOAT } else if (val_type == 'f') { union { uint32_t i; float f; } fpu = {val}; diff --git a/py/builtinhelp.c b/py/builtinhelp.c index c9992906dd..7106f3cedd 100644 --- a/py/builtinhelp.c +++ b/py/builtinhelp.c @@ -69,7 +69,7 @@ STATIC void mp_help_add_from_names(mp_obj_t list, const char *name) { while (*name) { size_t l = strlen(name); // name should end in '.py' and we strip it off - mp_obj_list_append(list, mp_obj_new_str(name, l - 3, false)); + mp_obj_list_append(list, mp_obj_new_str(name, l - 3)); name += l + 1; } } diff --git a/py/builtinimport.c b/py/builtinimport.c index 04ce667234..9235e946c6 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -434,7 +434,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { DEBUG_printf("%.*s is dir\n", vstr_len(&path), vstr_str(&path)); // https://docs.python.org/3/reference/import.html // "Specifically, any module that contains a __path__ attribute is considered a package." - mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path), false)); + mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path))); size_t orig_path_len = path.len; vstr_add_char(&path, PATH_SEP_CHAR); vstr_add_str(&path, "__init__.py"); diff --git a/py/modbuiltins.c b/py/modbuiltins.c index 65c03d5231..ebff5f5c0c 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -159,12 +159,12 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { } else { mp_raise_ValueError("chr() arg not in range(0x110000)"); } - return mp_obj_new_str(str, len, true); + return mp_obj_new_str_via_qstr(str, len); #else mp_int_t ord = mp_obj_get_int(o_in); if (0 <= ord && ord <= 0xff) { char str[1] = {ord}; - return mp_obj_new_str(str, 1, true); + return mp_obj_new_str_via_qstr(str, 1); } else { mp_raise_ValueError("chr() arg not in range(256)"); } diff --git a/py/modio.c b/py/modio.c index 353a002865..828bcec464 100644 --- a/py/modio.c +++ b/py/modio.c @@ -176,7 +176,7 @@ STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) { return MP_OBJ_FROM_PTR(o); } - mp_obj_t path_out = mp_obj_new_str(path_buf.buf, path_buf.len, false); + mp_obj_t path_out = mp_obj_new_str(path_buf.buf, path_buf.len); return mp_builtin_open(1, &path_out, (mp_map_t*)&mp_const_empty_map); } MP_DEFINE_CONST_FUN_OBJ_2(resource_stream_obj, resource_stream); diff --git a/py/obj.h b/py/obj.h index 77f0f22985..31c3ce95c8 100644 --- a/py/obj.h +++ b/py/obj.h @@ -637,7 +637,8 @@ mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value); mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base); mp_obj_t mp_obj_new_int_from_ll(long long val); // this must return a multi-precision integer object (or raise an overflow exception) mp_obj_t mp_obj_new_int_from_ull(unsigned long long val); // this must return a multi-precision integer object (or raise an overflow exception) -mp_obj_t mp_obj_new_str(const char* data, size_t len, bool make_qstr_if_not_already); +mp_obj_t mp_obj_new_str(const char* data, size_t len); +mp_obj_t mp_obj_new_str_via_qstr(const char* data, size_t len); mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr); mp_obj_t mp_obj_new_bytes(const byte* data, size_t len); mp_obj_t mp_obj_new_bytearray(size_t n, void *items); diff --git a/py/objstr.c b/py/objstr.c index 51da7a4182..5c464ba7d6 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -176,7 +176,7 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ mp_raise_msg(&mp_type_UnicodeError, NULL); } #endif - return mp_obj_new_str(bufinfo.buf, bufinfo.len, false); + return mp_obj_new_str(bufinfo.buf, bufinfo.len); } } } @@ -423,7 +423,7 @@ STATIC mp_obj_t bytes_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (MICROPY_PY_BUILTINS_STR_UNICODE || type == &mp_type_bytes) { return MP_OBJ_NEW_SMALL_INT(self_data[index_val]); } else { - return mp_obj_new_str((char*)&self_data[index_val], 1, true); + return mp_obj_new_str_via_qstr((char*)&self_data[index_val], 1); } } else { return MP_OBJ_NULL; // op not supported @@ -1046,7 +1046,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar } else { const char *lookup; for (lookup = field_name; lookup < field_name_top && *lookup != '.' && *lookup != '['; lookup++); - mp_obj_t field_q = mp_obj_new_str(field_name, lookup - field_name, true/*?*/); + mp_obj_t field_q = mp_obj_new_str_via_qstr(field_name, lookup - field_name); // should it be via qstr? field_name = lookup; mp_map_elem_t *key_elem = mp_map_lookup(kwargs, field_q, MP_MAP_LOOKUP); if (key_elem == NULL) { @@ -1413,7 +1413,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ } ++str; } - mp_obj_t k_obj = mp_obj_new_str((const char*)key, str - key, true); + mp_obj_t k_obj = mp_obj_new_str_via_qstr((const char*)key, str - key); arg = mp_obj_dict_get(dict, k_obj); str++; } @@ -1992,6 +1992,11 @@ mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, siz return MP_OBJ_FROM_PTR(o); } +// Create a str using a qstr to store the data; may use existing or new qstr. +mp_obj_t mp_obj_new_str_via_qstr(const char* data, size_t len) { + return MP_OBJ_NEW_QSTR(qstr_from_strn(data, len)); +} + // Create a str/bytes object from the given vstr. The vstr buffer is resized to // the exact length required and then reused for the str/bytes object. The vstr // is cleared and can safely be passed to vstr_free if it was heap allocated. @@ -2022,25 +2027,20 @@ mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr) { return MP_OBJ_FROM_PTR(o); } -mp_obj_t mp_obj_new_str(const char* data, size_t len, bool make_qstr_if_not_already) { - if (make_qstr_if_not_already) { - // use existing, or make a new qstr - return MP_OBJ_NEW_QSTR(qstr_from_strn(data, len)); +mp_obj_t mp_obj_new_str(const char* data, size_t len) { + qstr q = qstr_find_strn(data, len); + if (q != MP_QSTR_NULL) { + // qstr with this data already exists + return MP_OBJ_NEW_QSTR(q); } else { - qstr q = qstr_find_strn(data, len); - if (q != MP_QSTR_NULL) { - // qstr with this data already exists - return MP_OBJ_NEW_QSTR(q); - } else { - // no existing qstr, don't make one - return mp_obj_new_str_of_type(&mp_type_str, (const byte*)data, len); - } + // no existing qstr, don't make one + return mp_obj_new_str_of_type(&mp_type_str, (const byte*)data, len); } } mp_obj_t mp_obj_str_intern(mp_obj_t str) { GET_STR_DATA_LEN(str, data, len); - return MP_OBJ_NEW_QSTR(qstr_from_strn((const char*)data, len)); + return mp_obj_new_str_via_qstr((const char*)data, len); } mp_obj_t mp_obj_new_bytes(const byte* data, size_t len) { @@ -2138,7 +2138,7 @@ STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) { mp_obj_str8_it_t *self = MP_OBJ_TO_PTR(self_in); GET_STR_DATA_LEN(self->str, str, len); if (self->cur < len) { - mp_obj_t o_out = mp_obj_new_str((const char*)str + self->cur, 1, true); + mp_obj_t o_out = mp_obj_new_str_via_qstr((const char*)str + self->cur, 1); self->cur += 1; return o_out; } else { diff --git a/py/objstrunicode.c b/py/objstrunicode.c index 29f7695b73..a1f54b8a21 100644 --- a/py/objstrunicode.c +++ b/py/objstrunicode.c @@ -216,7 +216,7 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { ++len; } } - return mp_obj_new_str((const char*)s, len, true); // This will create a one-character string + return mp_obj_new_str_via_qstr((const char*)s, len); // This will create a one-character string } else { return MP_OBJ_NULL; // op not supported } @@ -291,7 +291,7 @@ STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) { if (self->cur < len) { const byte *cur = str + self->cur; const byte *end = utf8_next_char(str + self->cur); - mp_obj_t o_out = mp_obj_new_str((const char*)cur, end - cur, true); + mp_obj_t o_out = mp_obj_new_str_via_qstr((const char*)cur, end - cur); self->cur += end - cur; return o_out; } else { From 1f1d5194d775ad996f1d341c1a44b56af7ea4d4c Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 16 Nov 2017 13:53:04 +1100 Subject: [PATCH 027/828] py/objstr: Make mp_obj_new_str_of_type check for existing interned qstr. The function mp_obj_new_str_of_type is a general str object constructor used in many places in the code to create either a str or bytes object. When creating a str it should first check if the string data already exists as an interned qstr, and if so then return the qstr object. This patch makes the function have such behaviour, which helps to reduce heap usage by reusing existing interned data where possible. The old behaviour of mp_obj_new_str_of_type (which didn't check for existing interned data) is made available through the function mp_obj_new_str_copy, but should only be used in very special cases. One consequence of this patch is that the following expression is now True: 'abc' is ' abc '.split()[0] --- py/objstr.c | 26 +++++++++++++++++++------- py/objstr.h | 1 + py/parse.c | 2 +- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/py/objstr.c b/py/objstr.c index 5c464ba7d6..bca2af801b 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -164,7 +164,7 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ mp_raise_msg(&mp_type_UnicodeError, NULL); } #endif - mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_of_type(type, NULL, str_len)); + mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_copy(type, NULL, str_len)); o->data = str_data; o->hash = str_hash; return MP_OBJ_FROM_PTR(o); @@ -205,7 +205,7 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size if (str_hash == 0) { str_hash = qstr_compute_hash(str_data, str_len); } - mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_of_type(&mp_type_bytes, NULL, str_len)); + mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_copy(&mp_type_bytes, NULL, str_len)); o->data = str_data; o->hash = str_hash; return MP_OBJ_FROM_PTR(o); @@ -226,7 +226,7 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size // check if argument has the buffer protocol mp_buffer_info_t bufinfo; if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_READ)) { - return mp_obj_new_str_of_type(&mp_type_bytes, bufinfo.buf, bufinfo.len); + return mp_obj_new_bytes(bufinfo.buf, bufinfo.len); } vstr_t vstr; @@ -1977,8 +1977,9 @@ const mp_obj_type_t mp_type_bytes = { const mp_obj_str_t mp_const_empty_bytes_obj = {{&mp_type_bytes}, 0, 0, (const byte*)""}; // Create a str/bytes object using the given data. New memory is allocated and -// the data is copied across. -mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, size_t len) { +// the data is copied across. This function should only be used if the type is bytes, +// or if the type is str and the string data is known to be not interned. +mp_obj_t mp_obj_new_str_copy(const mp_obj_type_t *type, const byte* data, size_t len) { mp_obj_str_t *o = m_new_obj(mp_obj_str_t); o->base.type = type; o->len = len; @@ -1992,6 +1993,17 @@ mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, siz return MP_OBJ_FROM_PTR(o); } +// Create a str/bytes object using the given data. If the type is str and the string +// data is already interned, then a qstr object is returned. Otherwise new memory is +// allocated for the object and the data is copied across. +mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, size_t len) { + if (type == &mp_type_str) { + return mp_obj_new_str((const char*)data, len); + } else { + return mp_obj_new_bytes(data, len); + } +} + // Create a str using a qstr to store the data; may use existing or new qstr. mp_obj_t mp_obj_new_str_via_qstr(const char* data, size_t len) { return MP_OBJ_NEW_QSTR(qstr_from_strn(data, len)); @@ -2034,7 +2046,7 @@ mp_obj_t mp_obj_new_str(const char* data, size_t len) { return MP_OBJ_NEW_QSTR(q); } else { // no existing qstr, don't make one - return mp_obj_new_str_of_type(&mp_type_str, (const byte*)data, len); + return mp_obj_new_str_copy(&mp_type_str, (const byte*)data, len); } } @@ -2044,7 +2056,7 @@ mp_obj_t mp_obj_str_intern(mp_obj_t str) { } mp_obj_t mp_obj_new_bytes(const byte* data, size_t len) { - return mp_obj_new_str_of_type(&mp_type_bytes, data, len); + return mp_obj_new_str_copy(&mp_type_bytes, data, len); } bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) { diff --git a/py/objstr.h b/py/objstr.h index 82501a763e..4e55cad091 100644 --- a/py/objstr.h +++ b/py/objstr.h @@ -65,6 +65,7 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t void mp_str_print_json(const mp_print_t *print, const byte *str_data, size_t str_len); mp_obj_t mp_obj_str_format(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs); mp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args); +mp_obj_t mp_obj_new_str_copy(const mp_obj_type_t *type, const byte* data, size_t len); mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, size_t len); mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in); diff --git a/py/parse.c b/py/parse.c index 8c51b03498..f7fe30418c 100644 --- a/py/parse.c +++ b/py/parse.c @@ -417,7 +417,7 @@ STATIC void push_result_token(parser_t *parser, const rule_t *rule) { pn = mp_parse_node_new_leaf(lex->tok_kind == MP_TOKEN_STRING ? MP_PARSE_NODE_STRING : MP_PARSE_NODE_BYTES, qst); } else { // not interned, make a node holding a pointer to the string/bytes object - mp_obj_t o = mp_obj_new_str_of_type( + mp_obj_t o = mp_obj_new_str_copy( lex->tok_kind == MP_TOKEN_STRING ? &mp_type_str : &mp_type_bytes, (const byte*)lex->vstr.buf, lex->vstr.len); pn = make_node_const_object(parser, lex->tok_line, o); From 8d956c26d150749375115346f4ca319455107587 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 16 Nov 2017 14:02:28 +1100 Subject: [PATCH 028/828] py/objstr: When constructing str from bytes, check for existing qstr. This patch uses existing qstr data where possible when constructing a str from a bytes object. --- py/objstr.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/py/objstr.c b/py/objstr.c index bca2af801b..1ff5132d29 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -164,6 +164,13 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ mp_raise_msg(&mp_type_UnicodeError, NULL); } #endif + + // Check if a qstr with this data already exists + qstr q = qstr_find_strn((const char*)str_data, str_len); + if (q != MP_QSTR_NULL) { + return MP_OBJ_NEW_QSTR(q); + } + mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_copy(type, NULL, str_len)); o->data = str_data; o->hash = str_hash; From 31550a52e4b9ff5797755b54c415e365ab1d64d7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 6 Oct 2017 10:57:51 +1100 Subject: [PATCH 029/828] docs/library/network: Enhance AbstractNIC.status to take an argument. The argument is optional and if given should be a string naming the status variable to query. --- docs/library/network.rst | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/docs/library/network.rst b/docs/library/network.rst index 99a7c242c0..a1190a5740 100644 --- a/docs/library/network.rst +++ b/docs/library/network.rst @@ -98,10 +98,20 @@ parameter should be `id`. duration and other parameters. Where possible, parameter names should match those in connect(). - .. method:: status() + .. method:: status([param]) - Return detailed status of the interface, values are dependent - on the network medium/technology. + Query dynamic status information of the interface. When called with no + argument the return value describes the network link status. Otherwise + *param* should be a string naming the particular status parameter to + retrieve. + + The return types and values are dependent on the network + medium/technology. Some of the parameters that may be supported are: + + * WiFi STA: use ``'rssi'`` to retrieve the RSSI of the AP signal + * WiFi AP: use ``'stations'`` to retrieve a list of all the STAs + connected to the AP. The list contains tuples of the form + (MAC, RSSI). .. method:: ifconfig([(ip, subnet, gateway, dns)]) @@ -118,7 +128,7 @@ parameter should be `id`. Get or set general network interface parameters. These methods allow to work with additional parameters beyond standard IP configuration (as dealt with by `ifconfig()`). These include network-specific and hardware-specific - parameters and status values. For setting parameters, the keyword argument + parameters. For setting parameters, the keyword argument syntax should be used, and multiple parameters can be set at once. For querying, a parameter name should be quoted as a string, and only one parameter can be queried at a time:: @@ -128,8 +138,6 @@ parameter should be `id`. # Query params one by one print(ap.config('essid')) print(ap.config('channel')) - # Extended status information also available this way - print(sta.config('rssi')) .. only:: port_pyboard From ccaa5f5b0bad69f0f0ea81151e34c218fe13ce66 Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Sun, 15 Oct 2017 18:26:58 +0100 Subject: [PATCH 030/828] drivers/nrf24l01: Make driver and test run on pyboard, ESP8266, ESP32. --- drivers/nrf24l01/nrf24l01.py | 9 +++--- drivers/nrf24l01/nrf24l01test.py | 53 +++++++++++++++++++++++++------- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/drivers/nrf24l01/nrf24l01.py b/drivers/nrf24l01/nrf24l01.py index 7274a79278..a95d2b5cac 100644 --- a/drivers/nrf24l01/nrf24l01.py +++ b/drivers/nrf24l01/nrf24l01.py @@ -62,12 +62,11 @@ class NRF24L01: # init the SPI bus and pins self.init_spi(4000000) - cs.init(cs.OUT, value=1) - ce.init(ce.OUT, value=0) # reset everything - self.ce(0) - self.cs(1) + ce.init(ce.OUT, value=0) + cs.init(cs.OUT, value=1) + self.payload_size = payload_size self.pipe0_read_addr = None utime.sleep_ms(5) @@ -215,7 +214,7 @@ class NRF24L01: # blocking wait for tx complete def send(self, buf, timeout=500): - send_nonblock = self.send_start(buf) + self.send_start(buf) start = utime.ticks_ms() result = None while result is None and utime.ticks_diff(utime.ticks_ms(), start) < timeout: diff --git a/drivers/nrf24l01/nrf24l01test.py b/drivers/nrf24l01/nrf24l01test.py index 5413511c3b..876b2bbfa2 100644 --- a/drivers/nrf24l01/nrf24l01test.py +++ b/drivers/nrf24l01/nrf24l01test.py @@ -1,14 +1,38 @@ -"""Test for nrf24l01 module.""" +"""Test for nrf24l01 module. Portable between MicroPython targets.""" -import struct +import sys +import ustruct as struct import utime from machine import Pin, SPI from nrf24l01 import NRF24L01 +from micropython import const + +# Slave pause between receiving data and checking for further packets. +_RX_POLL_DELAY = const(15) +# Slave pauses an additional _SLAVE_SEND_DELAY ms after receiving data and before +# transmitting to allow the (remote) master time to get into receive mode. The +# master may be a slow device. Value tested with Pyboard, ESP32 and ESP8266. +_SLAVE_SEND_DELAY = const(10) + +if sys.platform == 'pyboard': + cfg = {'spi': 2, 'miso': 'Y7', 'mosi': 'Y8', 'sck': 'Y6', 'csn': 'Y5', 'ce': 'Y4'} +elif sys.platform == 'esp8266': # Hardware SPI + cfg = {'spi': 1, 'miso': 12, 'mosi': 13, 'sck': 14, 'csn': 4, 'ce': 5} +elif sys.platform == 'esp32': # Software SPI + cfg = {'spi': -1, 'miso': 32, 'mosi': 33, 'sck': 25, 'csn': 26, 'ce': 27} +else: + raise ValueError('Unsupported platform {}'.format(sys.platform)) pipes = (b'\xf0\xf0\xf0\xf0\xe1', b'\xf0\xf0\xf0\xf0\xd2') def master(): - nrf = NRF24L01(SPI(2), Pin('Y5'), Pin('Y4'), payload_size=8) + csn = Pin(cfg['csn'], mode=Pin.OUT, value=1) + ce = Pin(cfg['ce'], mode=Pin.OUT, value=0) + if cfg['spi'] == -1: + spi = SPI(-1, sck=Pin(cfg['sck']), mosi=Pin(cfg['mosi']), miso=Pin(cfg['miso'])) + nrf = NRF24L01(spi, csn, ce, payload_size=8) + else: + nrf = NRF24L01(SPI(cfg['spi']), csn, ce, payload_size=8) nrf.open_tx_pipe(pipes[0]) nrf.open_rx_pipe(1, pipes[1]) @@ -60,7 +84,13 @@ def master(): print('master finished sending; successes=%d, failures=%d' % (num_successes, num_failures)) def slave(): - nrf = NRF24L01(SPI(2), Pin('Y5'), Pin('Y4'), payload_size=8) + csn = Pin(cfg['csn'], mode=Pin.OUT, value=1) + ce = Pin(cfg['ce'], mode=Pin.OUT, value=0) + if cfg['spi'] == -1: + spi = SPI(-1, sck=Pin(cfg['sck']), mosi=Pin(cfg['mosi']), miso=Pin(cfg['miso'])) + nrf = NRF24L01(spi, csn, ce, payload_size=8) + else: + nrf = NRF24L01(SPI(cfg['spi']), csn, ce, payload_size=8) nrf.open_tx_pipe(pipes[1]) nrf.open_rx_pipe(1, pipes[0]) @@ -69,7 +99,6 @@ def slave(): print('NRF24L01 slave mode, waiting for packets... (ctrl-C to stop)') while True: - machine.idle() if nrf.any(): while nrf.any(): buf = nrf.recv() @@ -81,8 +110,10 @@ def slave(): else: led.off() led_state >>= 1 - utime.sleep_ms(15) + utime.sleep_ms(_RX_POLL_DELAY) + # Give master time to get into receive mode. + utime.sleep_ms(_SLAVE_SEND_DELAY) nrf.stop_listening() try: nrf.send(struct.pack('i', millis)) @@ -99,9 +130,9 @@ except: print('NRF24L01 test module loaded') print('NRF24L01 pinout for test:') -print(' CE on Y4') -print(' CSN on Y5') -print(' SCK on Y6') -print(' MISO on Y7') -print(' MOSI on Y8') +print(' CE on', cfg['ce']) +print(' CSN on', cfg['csn']) +print(' SCK on', cfg['sck']) +print(' MISO on', cfg['miso']) +print(' MOSI on', cfg['mosi']) print('run nrf24l01test.slave() on slave, then nrf24l01test.master() on master') From 12ad64bc554fe33772c492efc55eb9290463048a Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 16 Nov 2017 16:01:47 +1100 Subject: [PATCH 031/828] extmod/vfs_fat: Mount FatFS on creation so VFS methods can be used. It's possible to use the methods (eg ilistdir) of a VFS FatFS object without it being mounted in the VFS itself. This previously worked but only because FatFS was "mounting" the filesystem automatically when any function (eg f_opendir) was called. But it didn't work for ports that used synchronisation objects (_FS_REENTRANT) because they are only initialised via a call to f_mount. So, call f_mount explicitly when creating a new FatFS object so that everything is set up correctly. Then also provide a finaliser to do the f_umount call, but only if synchronisation objects are enabled (since otherwise the f_umount call does nothing). --- extmod/vfs_fat.c | 34 ++++++++++++++++++++++++++-------- extmod/vfs_fat.h | 1 + 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 9942ddeb55..0076df2626 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -69,9 +69,28 @@ STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_ mp_load_method(args[0], MP_QSTR_count, vfs->u.old.count); } + // mount the block device so the VFS methods can be used + FRESULT res = f_mount(&vfs->fatfs); + if (res == FR_NO_FILESYSTEM) { + // don't error out if no filesystem, to let mkfs()/mount() create one if wanted + vfs->flags |= FSUSER_NO_FILESYSTEM; + } else if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + return MP_OBJ_FROM_PTR(vfs); } +#if _FS_REENTRANT +STATIC mp_obj_t fat_vfs_del(mp_obj_t self_in) { + mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(self_in); + // f_umount only needs to be called to release the sync object + f_umount(&self->fatfs); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_del_obj, fat_vfs_del); +#endif + STATIC mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) { // create new object fs_user_mount_t *vfs = MP_OBJ_TO_PTR(fat_vfs_make_new(&mp_fat_vfs_type, 1, 0, &bdev_in)); @@ -291,10 +310,8 @@ STATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs self->writeblocks[0] = MP_OBJ_NULL; } - // mount the block device - FRESULT res = f_mount(&self->fatfs); - // check if we need to make the filesystem + FRESULT res = (self->flags & FSUSER_NO_FILESYSTEM) ? FR_NO_FILESYSTEM : FR_OK; if (res == FR_NO_FILESYSTEM && mp_obj_is_true(mkfs)) { uint8_t working_buf[_MAX_SS]; res = f_mkfs(&self->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf)); @@ -302,22 +319,23 @@ STATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); } + self->flags &= ~FSUSER_NO_FILESYSTEM; return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_fat_mount_obj, vfs_fat_mount); STATIC mp_obj_t vfs_fat_umount(mp_obj_t self_in) { - fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); - FRESULT res = f_umount(&self->fatfs); - if (res != FR_OK) { - mp_raise_OSError(fresult_to_errno_table[res]); - } + (void)self_in; + // keep the FAT filesystem mounted internally so the VFS methods can still be used return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_umount_obj, vfs_fat_umount); STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = { + #if _FS_REENTRANT + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&fat_vfs_del_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&fat_vfs_mkfs_obj) }, { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&fat_vfs_open_obj) }, { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&fat_vfs_ilistdir_obj) }, diff --git a/extmod/vfs_fat.h b/extmod/vfs_fat.h index 443e4eda82..688452973c 100644 --- a/extmod/vfs_fat.h +++ b/extmod/vfs_fat.h @@ -35,6 +35,7 @@ #define FSUSER_NATIVE (0x0001) // readblocks[2]/writeblocks[2] contain native func #define FSUSER_FREE_OBJ (0x0002) // fs_user_mount_t obj should be freed on umount #define FSUSER_HAVE_IOCTL (0x0004) // new protocol with ioctl +#define FSUSER_NO_FILESYSTEM (0x0008) // the block device has no filesystem on it typedef struct _fs_user_mount_t { mp_obj_base_t base; From bbac2df0cfde1a8ff9d203decf0ecf5a443a2eb7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 20 Nov 2017 14:19:12 +1100 Subject: [PATCH 032/828] stm32/boards/stm32f746_af.csv: Fix typos in AF table. --- ports/stm32/boards/stm32f746_af.csv | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/ports/stm32/boards/stm32f746_af.csv b/ports/stm32/boards/stm32f746_af.csv index eabc9ab3ba..8069edc7b9 100644 --- a/ports/stm32/boards/stm32f746_af.csv +++ b/ports/stm32/boards/stm32f746_af.csv @@ -5,7 +5,7 @@ PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B, PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,,,LCD_R1,EVENTOUT PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT -PortA,PA5,,TIM2_CH1/TIM2_ETR,TIM8_CH1N,SPI1_SCK/I2S1_CK,,,,,,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,DCMI_PIXCLK,LCD_G2,EVENTOUT PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SD,,,,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT PortA,PA8,MCO1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,LCD_R6,EVENTOUT @@ -13,16 +13,16 @@ PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,,,,DCMI_D0,,EVENTO PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT -PortA,PA13,JTMS,SWDIO,,,,,,,,,,,,,,EVENTOUT -PortA,PA14,JTCK,SWCLK,,,,,,,,,,,,,,EVENTOUT -PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,HDMICE,CSPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,,UART4_RTS,,,,,,,EVENTOUT -PortB,PB0,,TIM1_CH2N,TIM3_CH3T,IM8_CH2N,,,,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT -PortB,PB1,,TIM1_CH3N,TIM3_CH4T,IM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT +PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,HDMI_CEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,,UART4_RTS,,,,,,,EVENTOUT +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT PortB,PB2,,,,,,,SAI1_SD_A,SPI3_MOSI/I2S3_SD,,QUADSPI_CLK,,,,,,EVENTOUT PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,,,,,,,,EVENTOUT PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,SPI2_NSS/I2S2_WS,,,,,,,,EVENTOUT PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,,EVENTOUT -PortB,PB6,,,TIM4_CH1,HDMICEC,I2C1_SCL,,,USART1_TX,,CAN2_TX,QUADSPI_BK1_NCS,,FMC_SDNE1,DCMI_D5,,EVENTOUT +PortB,PB6,,,TIM4_CH1,HDMI_CEC,I2C1_SCL,,,USART1_TX,,CAN2_TX,QUADSPI_BK1_NCS,,FMC_SDNE1,DCMI_D5,,EVENTOUT PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,FMC_NL,DCMI_VSYNC,,EVENTOUT PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,,,,CAN1_RX,,ETH_MII_TXD3,SDMMC1_D4,DCMI_D6,LCD_B6,EVENTOUT PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,CAN1_TX,,,SDMMC1_D5,DCMI_D7,LCD_B7,EVENTOUT @@ -168,4 +168,3 @@ PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT - From 3e9e9b07bac2d09b0db812d3b31fb6c1af3d5c95 Mon Sep 17 00:00:00 2001 From: Jaroslav Sykora Date: Sun, 19 Nov 2017 15:27:31 +0100 Subject: [PATCH 033/828] stm32/boards: Add support for NUCLEO-F746ZG evaluation board. This is a low-cost evaluation kit board from ST based on the STM32 Nucleo-144 form factor. It uses the STM32F746ZG MCU in the LQFP144 package. The MCU has 1MB of flash and 320kB of System RAM. Cortex-M7 runs at up to 216MHz. --- .../boards/NUCLEO_F746ZG/mpconfigboard.h | 76 ++++ .../boards/NUCLEO_F746ZG/mpconfigboard.mk | 4 + ports/stm32/boards/NUCLEO_F746ZG/pins.csv | 68 +++ .../boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h | 429 ++++++++++++++++++ 4 files changed, 577 insertions(+) create mode 100644 ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h create mode 100644 ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk create mode 100644 ports/stm32/boards/NUCLEO_F746ZG/pins.csv create mode 100644 ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h diff --git a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h new file mode 100644 index 0000000000..c5b84938cd --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h @@ -0,0 +1,76 @@ +// This board is only confirmed to operate using DFU mode and openocd. +// DFU mode can be accessed by setting BOOT0 (see schematics) +// To use openocd run "OPENOCD_CONFIG=boards/openocd_stm32f7.cfg" in +// the make command. + +#define MICROPY_HW_BOARD_NAME "NUCLEO-F746ZG" +#define MICROPY_HW_MCU_NAME "STM32F746" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_HAS_SDCARD (0) +#define MICROPY_HW_HAS_MMA7660 (0) +#define MICROPY_HW_HAS_LIS3DSH (0) +#define MICROPY_HW_HAS_LCD (0) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_TIMER (1) +#define MICROPY_HW_ENABLE_SERVO (0) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_CAN (1) + +// HSE is 8MHz +// VCOClock = HSE * PLLN / PLLM = 8 MHz * 216 / 4 = 432 MHz +// SYSCLK = VCOClock / PLLP = 432 MHz / 2 = 216 MHz +// USB/SDMMC/RNG Clock = VCOClock / PLLQ = 432 MHz / 9 = 48 MHz +#define MICROPY_HW_CLK_PLLM (4) +#define MICROPY_HW_CLK_PLLN (216) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (9) + +// From the reference manual, for 2.7V to 3.6V +// 151-180 MHz => 5 wait states +// 181-210 MHz => 6 wait states +// 211-216 MHz => 7 wait states +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_7 // 210-216 MHz needs 7 wait states + +// UART config +#define MICROPY_HW_UART2_TX (pin_D5) +#define MICROPY_HW_UART2_RX (pin_D6) +#define MICROPY_HW_UART2_RTS (pin_D4) +#define MICROPY_HW_UART2_CTS (pin_D3) +#define MICROPY_HW_UART3_TX (pin_D8) +#define MICROPY_HW_UART3_RX (pin_D9) +#define MICROPY_HW_UART6_TX (pin_G14) +#define MICROPY_HW_UART6_RX (pin_G9) +#define MICROPY_HW_UART_REPL PYB_UART_3 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B8) +#define MICROPY_HW_I2C1_SDA (pin_B9) +#define MICROPY_HW_I2C3_SCL (pin_H7) +#define MICROPY_HW_I2C3_SDA (pin_H8) + +// SPI +#define MICROPY_HW_SPI3_NSS (pin_A4) +#define MICROPY_HW_SPI3_SCK (pin_B3) +#define MICROPY_HW_SPI3_MISO (pin_B4) +#define MICROPY_HW_SPI3_MOSI (pin_B5) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_C13) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_B0) // green +#define MICROPY_HW_LED2 (pin_B7) // blue +#define MICROPY_HW_LED3 (pin_B14) // red +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config (CN13 - USB OTG FS) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk new file mode 100644 index 0000000000..7c6bc4584a --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk @@ -0,0 +1,4 @@ +MCU_SERIES = f7 +CMSIS_MCU = STM32F746xx +AF_FILE = boards/stm32f746_af.csv +LD_FILE = boards/stm32f746.ld diff --git a/ports/stm32/boards/NUCLEO_F746ZG/pins.csv b/ports/stm32/boards/NUCLEO_F746ZG/pins.csv new file mode 100644 index 0000000000..897b1473e7 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F746ZG/pins.csv @@ -0,0 +1,68 @@ +A0,PA3 +A1,PC0 +A2,PC3 +A3,PF3 +A4,PF5 +A5,PF10 +D0,PG9 +D1,PG14 +D2,PF15 +D3,PE13 +D4,PF14 +D5,PE11 +D6,PE9 +D7,PF13 +D8,PF12 +D9,PD15 +D10,PD14 +D11,PA7 +D12,PA6 +D13,PA5 +D14,PB9 +D15,PB8 +D16,PC6 +D17,PB15 +D18,PB13 +D19,PB12 +D20,PA15 +D21,PC7 +D22,PB5 +D23,PB3 +D24,PA4 +D25,PB4 +LED1,PB0 +LED2,PB7 +LED3,PB14 +SW,PC13 +TP1,PH2 +TP2,PI8 +TP3,PH15 +AUDIO_INT,PD6 +AUDIO_SDA,PH8 +AUDIO_SCL,PH7 +EXT_SDA,PB9 +EXT_SCL,PB8 +EXT_RST,PG3 +SD_SW,PC13 +LCD_BL_CTRL,PK3 +LCD_INT,PI13 +LCD_SDA,PH8 +LCD_SCL,PH7 +OTG_FS_POWER,PD5 +OTG_FS_OVER_CURRENT,PD4 +OTG_HS_OVER_CURRENT,PE3 +USB_VBUS,PJ12 +USB_ID,PA10 +USB_DM,PA11 +USB_DP,PA12 +VCP_TX,PD8 +VCP_RX,PD9 +UART2_TX,PD5 +UART2_RX,PD6 +UART2_RTS,PD4 +UART2_CTS,PD3 +UART6_TX,PG14 +UART6_RX,PG9 +SPI_B_NSS,PA4 +SPI_B_SCK,PB3 +SPI_B_MOSI,PB5 diff --git a/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h new file mode 100644 index 0000000000..e1aa4578d5 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h @@ -0,0 +1,429 @@ +/** + ****************************************************************************** + * @file stm32f7xx_hal_conf.h + * @author MCD Application Team + * @version V1.0.1 + * @date 25-June-2015 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7xx_HAL_CONF_H +#define __STM32F7xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +#define USE_USB_FS + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CEC_MODULE_ENABLED */ +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_MODULE_ENABLED +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LPTIM_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +/* #define HAL_QSPI_MODULE_ENABLED */ +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +/* #define HAL_SPDIFRX_MODULE_ENABLED */ +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## Timeout Configuration ######################### */ +/** + * @brief This is the HAL configuration section + */ +#define HAL_ACCURATE_TIMEOUT_ENABLED 0 +#define HAL_TIMEOUT_VALUE 0x1FFFFFF + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)32000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define ART_ACCLERATOR_ENABLE 1 /* To enable instruction cache and prefetch */ + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 1 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)5) /* 5 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)5) /* 5 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ +/* LAN8742A PHY Address*/ +#define LAN8742A_PHY_ADDRESS 0x00 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x00000FFF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f7xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f7xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f7xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f7xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f7xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f7xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CEC_MODULE_ENABLED + #include "stm32f7xx_hal_cec.h" +#endif /* HAL_CEC_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f7xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f7xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f7xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f7xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f7xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f7xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f7xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f7xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f7xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f7xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f7xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f7xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f7xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f7xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f7xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED + #include "stm32f7xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f7xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f7xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32f7xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f7xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f7xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f7xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f7xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPDIFRX_MODULE_ENABLED + #include "stm32f7xx_hal_spdifrx.h" +#endif /* HAL_SPDIFRX_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f7xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f7xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f7xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f7xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f7xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f7xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f7xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f7xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f7xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ From 6906255dcdd8d8ff04efd1651c7a503a230a3523 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 20 Nov 2017 15:25:28 +1100 Subject: [PATCH 034/828] stm32/boards: Remove obsolete and unused board-specific defines. These board-level macros have been completely replaced by feature-level config options. --- ports/stm32/boards/CERB40/mpconfigboard.h | 2 -- ports/stm32/boards/HYDRABUS/mpconfigboard.h | 2 -- ports/stm32/boards/OLIMEX_E407/mpconfigboard.h | 2 -- ports/stm32/boards/STM32F4DISC/mpconfigboard.h | 2 -- ports/stm32/boards/STM32F7DISC/mpconfigboard.h | 2 -- 5 files changed, 10 deletions(-) diff --git a/ports/stm32/boards/CERB40/mpconfigboard.h b/ports/stm32/boards/CERB40/mpconfigboard.h index 284de7a40f..e668ba4e14 100644 --- a/ports/stm32/boards/CERB40/mpconfigboard.h +++ b/ports/stm32/boards/CERB40/mpconfigboard.h @@ -1,5 +1,3 @@ -#define CERB40 - #define MICROPY_HW_BOARD_NAME "Cerb40" #define MICROPY_HW_MCU_NAME "STM32F405RG" diff --git a/ports/stm32/boards/HYDRABUS/mpconfigboard.h b/ports/stm32/boards/HYDRABUS/mpconfigboard.h index 38fba9787a..8eaa367474 100644 --- a/ports/stm32/boards/HYDRABUS/mpconfigboard.h +++ b/ports/stm32/boards/HYDRABUS/mpconfigboard.h @@ -1,5 +1,3 @@ -#define HYDRABUSV10 - #define MICROPY_HW_BOARD_NAME "HydraBus1.0" #define MICROPY_HW_MCU_NAME "STM32F4" diff --git a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h index 5ede682647..86dfd1166c 100644 --- a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h +++ b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h @@ -1,5 +1,3 @@ -#define STM32E407 - #define MICROPY_HW_BOARD_NAME "OLIMEX STM32-E407" #define MICROPY_HW_MCU_NAME "STM32F407" diff --git a/ports/stm32/boards/STM32F4DISC/mpconfigboard.h b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h index 1058755158..688a1ef621 100644 --- a/ports/stm32/boards/STM32F4DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h @@ -1,5 +1,3 @@ -#define STM32F4DISC - #define MICROPY_HW_BOARD_NAME "F4DISC" #define MICROPY_HW_MCU_NAME "STM32F407" diff --git a/ports/stm32/boards/STM32F7DISC/mpconfigboard.h b/ports/stm32/boards/STM32F7DISC/mpconfigboard.h index 44a39c0a1a..41d49f64b5 100644 --- a/ports/stm32/boards/STM32F7DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F7DISC/mpconfigboard.h @@ -1,5 +1,3 @@ -#define STM32F7DISC - #define MICROPY_HW_BOARD_NAME "F7DISC" #define MICROPY_HW_MCU_NAME "STM32F746" From 811ddcc65f9fb666228a9477139f4fceb31240dd Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 20 Nov 2017 15:28:04 +1100 Subject: [PATCH 035/828] stm32/led: Remove unused LED enum constants. --- ports/stm32/led.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/ports/stm32/led.h b/ports/stm32/led.h index f1b05d1e28..2c872e9c5f 100644 --- a/ports/stm32/led.h +++ b/ports/stm32/led.h @@ -27,21 +27,10 @@ #define MICROPY_INCLUDED_STMHAL_LED_H typedef enum { - // PYBv3 - PYB_LED_R1 = 1, - PYB_LED_R2 = 2, - PYB_LED_G1 = 3, - PYB_LED_G2 = 4, - // PYBv4 PYB_LED_RED = 1, PYB_LED_GREEN = 2, PYB_LED_YELLOW = 3, PYB_LED_BLUE = 4, - //STM32F4DISC - PYB_LED_R = 1, - PYB_LED_G = 2, - PYB_LED_B = 3, - PYB_LED_O = 4, } pyb_led_t; void led_init(void); From da154fdaf933e6546ae4d6888af1a79a76d71b4c Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 1 Apr 2017 23:52:24 +1100 Subject: [PATCH 036/828] py: Add config option to disable multiple inheritance. This patch introduces a new compile-time config option to disable multiple inheritance at the Python level: MICROPY_MULTIPLE_INHERITANCE. It is enabled by default. Disabling multiple inheritance eliminates a lot of recursion in the call graph (which is important for some embedded systems), and can be used to reduce code size for ports that are really constrained (by around 200 bytes for Thumb2 archs). With multiple inheritance disabled all tests in the test-suite pass except those that explicitly test for multiple inheritance. --- py/mpconfig.h | 7 +++++++ py/objtype.c | 14 +++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/py/mpconfig.h b/py/mpconfig.h index 4209b32c6e..095b7ef7b9 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -666,6 +666,13 @@ typedef double mp_float_t; /*****************************************************************************/ /* Fine control over Python builtins, classes, modules, etc */ +// Whether to support multiple inheritance of Python classes. Multiple +// inheritance makes some C functions inherently recursive, and adds a bit of +// code overhead. +#ifndef MICROPY_MULTIPLE_INHERITANCE +#define MICROPY_MULTIPLE_INHERITANCE (1) +#endif + // Whether to implement attributes on functions #ifndef MICROPY_PY_FUNCTION_ATTRS #define MICROPY_PY_FUNCTION_ATTRS (0) diff --git a/py/objtype.c b/py/objtype.c index a8376a306e..01d248256a 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -67,6 +67,7 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t } else if (type->parent == NULL) { // No parents so end search here. return count; + #if MICROPY_MULTIPLE_INHERITANCE } else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) { // Multiple parents, search through them all recursively. const mp_obj_tuple_t *parent_tuple = type->parent; @@ -78,6 +79,7 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t count += instance_count_native_bases(bt, last_native_base); } return count; + #endif } else { // A single parent, use iteration to continue the search. type = type->parent; @@ -172,6 +174,7 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_ if (type->parent == NULL) { DEBUG_printf("mp_obj_class_lookup: No more parents\n"); return; + #if MICROPY_MULTIPLE_INHERITANCE } else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) { const mp_obj_tuple_t *parent_tuple = type->parent; const mp_obj_t *item = parent_tuple->items; @@ -192,6 +195,7 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_ // search last base (simple tail recursion elimination) assert(MP_OBJ_IS_TYPE(*item, &mp_type_type)); type = (mp_obj_type_t*)MP_OBJ_TO_PTR(*item); + #endif } else { type = type->parent; } @@ -247,7 +251,7 @@ STATIC void instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args) { assert(mp_obj_is_instance_type(self)); - const mp_obj_type_t *native_base; + const mp_obj_type_t *native_base = NULL; size_t num_native_bases = instance_count_native_bases(self, &native_base); assert(num_native_bases < 2); @@ -1022,7 +1026,11 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) o->protocol = ((mp_obj_type_t*)MP_OBJ_TO_PTR(bases_items[0]))->protocol; if (bases_len >= 2) { + #if MICROPY_MULTIPLE_INHERITANCE o->parent = MP_OBJ_TO_PTR(bases_tuple); + #else + mp_raise_NotImplementedError("multiple inheritance not supported"); + #endif } else { o->parent = MP_OBJ_TO_PTR(bases_items[0]); } @@ -1101,6 +1109,7 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (type->parent == NULL) { // no parents, do nothing + #if MICROPY_MULTIPLE_INHERITANCE } else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) { const mp_obj_tuple_t *parent_tuple = type->parent; size_t len = parent_tuple->len; @@ -1112,6 +1121,7 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { return; } } + #endif } else { mp_obj_class_lookup(&lookup, type->parent); if (dest[0] != MP_OBJ_NULL) { @@ -1158,6 +1168,7 @@ bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) { if (self->parent == NULL) { // type has no parents return false; + #if MICROPY_MULTIPLE_INHERITANCE } else if (((mp_obj_base_t*)self->parent)->type == &mp_type_tuple) { // get the base objects (they should be type objects) const mp_obj_tuple_t *parent_tuple = self->parent; @@ -1173,6 +1184,7 @@ bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) { // search last base (simple tail recursion elimination) object = *item; + #endif } else { // type has 1 parent object = MP_OBJ_FROM_PTR(self->parent); From 8667a5f0534238e3144adc35d487deb0ac5be5d6 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 28 Oct 2017 18:37:30 +0300 Subject: [PATCH 037/828] py/objnamedtuple: Allow to reuse namedtuple basic functionality. By declaring interface in objnamedtuple.h and introducing a helper allocation function. --- py/objnamedtuple.c | 32 ++++++++++++++------------------ py/objnamedtuple.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 py/objnamedtuple.h diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index 94f02dd696..e7de899cf9 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -30,20 +30,11 @@ #include "py/objtuple.h" #include "py/runtime.h" #include "py/objstr.h" +#include "py/objnamedtuple.h" #if MICROPY_PY_COLLECTIONS -typedef struct _mp_obj_namedtuple_type_t { - mp_obj_type_t base; - size_t n_fields; - qstr fields[]; -} mp_obj_namedtuple_type_t; - -typedef struct _mp_obj_namedtuple_t { - mp_obj_tuple_t tuple; -} mp_obj_namedtuple_t; - -STATIC size_t namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr name) { +size_t mp_obj_namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr name) { for (size_t i = 0; i < type->n_fields; i++) { if (type->fields[i] == name) { return i; @@ -88,7 +79,7 @@ STATIC void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { return; } #endif - size_t id = namedtuple_find_field((mp_obj_namedtuple_type_t*)self->tuple.base.type, attr); + size_t id = mp_obj_namedtuple_find_field((mp_obj_namedtuple_type_t*)self->tuple.base.type, attr); if (id == (size_t)-1) { return; } @@ -128,7 +119,7 @@ STATIC mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, memset(&tuple->items[n_args], 0, sizeof(mp_obj_t) * n_kw); for (size_t i = n_args; i < n_args + 2 * n_kw; i += 2) { qstr kw = mp_obj_str_get_qstr(args[i]); - size_t id = namedtuple_find_field(type, kw); + size_t id = mp_obj_namedtuple_find_field(type, kw); if (id == (size_t)-1) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); @@ -151,9 +142,18 @@ STATIC mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, return MP_OBJ_FROM_PTR(tuple); } -STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, size_t n_fields, mp_obj_t *fields) { +mp_obj_namedtuple_type_t *mp_obj_new_namedtuple_base(size_t n_fields, mp_obj_t *fields) { mp_obj_namedtuple_type_t *o = m_new_obj_var(mp_obj_namedtuple_type_t, qstr, n_fields); memset(&o->base, 0, sizeof(o->base)); + o->n_fields = n_fields; + for (size_t i = 0; i < n_fields; i++) { + o->fields[i] = mp_obj_str_get_qstr(fields[i]); + } + return o; +} + +STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, size_t n_fields, mp_obj_t *fields) { + mp_obj_namedtuple_type_t *o = mp_obj_new_namedtuple_base(n_fields, fields); o->base.base.type = &mp_type_type; o->base.name = name; o->base.print = namedtuple_print; @@ -164,10 +164,6 @@ STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, size_t n_fields, mp_obj_t o->base.subscr = mp_obj_tuple_subscr; o->base.getiter = mp_obj_tuple_getiter; o->base.parent = &mp_type_tuple; - o->n_fields = n_fields; - for (size_t i = 0; i < n_fields; i++) { - o->fields[i] = mp_obj_str_get_qstr(fields[i]); - } return MP_OBJ_FROM_PTR(o); } diff --git a/py/objnamedtuple.h b/py/objnamedtuple.h new file mode 100644 index 0000000000..d32af35afe --- /dev/null +++ b/py/objnamedtuple.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014-2017 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_OBJNAMEDTUPLE_H +#define MICROPY_INCLUDED_PY_OBJNAMEDTUPLE_H + +#include "py/objtuple.h" + +typedef struct _mp_obj_namedtuple_type_t { + mp_obj_type_t base; + size_t n_fields; + qstr fields[]; +} mp_obj_namedtuple_type_t; + +typedef struct _mp_obj_namedtuple_t { + mp_obj_tuple_t tuple; +} mp_obj_namedtuple_t; + +size_t mp_obj_namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr name); +mp_obj_namedtuple_type_t *mp_obj_new_namedtuple_base(size_t n_fields, mp_obj_t *fields); + +#endif // MICROPY_INCLUDED_PY_OBJNAMEDTUPLE_H From a07fc5b6403b9a8bf7e7cb64f857272e5346d7e2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 21 Nov 2017 15:01:38 +1100 Subject: [PATCH 038/828] py/objfloat: Allow float() to parse anything with the buffer protocol. This generalises and simplifies the code and follows CPython behaviour. --- py/objfloat.c | 12 ++++++------ tests/float/float1.py | 4 ++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/py/objfloat.c b/py/objfloat.c index 743287be63..75212a4d22 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -137,12 +137,11 @@ STATIC mp_obj_t float_make_new(const mp_obj_type_t *type_in, size_t n_args, size return mp_obj_new_float(0); case 1: - default: - if (MP_OBJ_IS_STR(args[0])) { - // a string, parse it - size_t l; - const char *s = mp_obj_str_get_data(args[0], &l); - return mp_parse_num_decimal(s, l, false, false, NULL); + default: { + mp_buffer_info_t bufinfo; + if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_READ)) { + // a textual representation, parse it + return mp_parse_num_decimal(bufinfo.buf, bufinfo.len, false, false, NULL); } else if (mp_obj_is_float(args[0])) { // a float, just return it return args[0]; @@ -150,6 +149,7 @@ STATIC mp_obj_t float_make_new(const mp_obj_type_t *type_in, size_t n_args, size // something else, try to cast it to a float return mp_obj_new_float(mp_obj_get_float(args[0])); } + } } } diff --git a/tests/float/float1.py b/tests/float/float1.py index c64f965a7d..54807e5ac9 100644 --- a/tests/float/float1.py +++ b/tests/float/float1.py @@ -36,6 +36,10 @@ try: except ValueError: print("ValueError") +# construct from something with the buffer protocol +print(float(b"1.2")) +print(float(bytearray(b"3.4"))) + # unary operators print(bool(0.0)) print(bool(1.2)) From d5cf5f70fdefa793d3e1fee9a26f03a1dd8c1d1e Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 22 Nov 2017 15:51:51 +1100 Subject: [PATCH 039/828] py/modbuiltins: Slightly simplify code in builtin round(). --- py/modbuiltins.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/py/modbuiltins.c b/py/modbuiltins.c index ebff5f5c0c..0c78832aca 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -457,16 +457,14 @@ STATIC mp_obj_t mp_builtin_round(size_t n_args, const mp_obj_t *args) { return o_in; } #if MICROPY_PY_BUILTINS_FLOAT - mp_int_t num_dig = 0; + mp_float_t val = mp_obj_get_float(o_in); if (n_args > 1) { - num_dig = mp_obj_get_int(args[1]); - mp_float_t val = mp_obj_get_float(o_in); + mp_int_t num_dig = mp_obj_get_int(args[1]); mp_float_t mult = MICROPY_FLOAT_C_FUN(pow)(10, num_dig); // TODO may lead to overflow mp_float_t rounded = MICROPY_FLOAT_C_FUN(nearbyint)(val * mult) / mult; return mp_obj_new_float(rounded); } - mp_float_t val = mp_obj_get_float(o_in); mp_float_t rounded = MICROPY_FLOAT_C_FUN(nearbyint)(val); return mp_obj_new_int_from_float(rounded); #else From df078e82136de80a6ff2d30db97a7411c45d4085 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 23 Nov 2017 10:45:12 +1100 Subject: [PATCH 040/828] tests/net_hosted: Add test for socket connect() and poll() behaviour. --- tests/net_hosted/connect_poll.py | 32 ++++++++++++++++++++++++++++ tests/net_hosted/connect_poll.py.exp | 3 +++ 2 files changed, 35 insertions(+) create mode 100644 tests/net_hosted/connect_poll.py create mode 100644 tests/net_hosted/connect_poll.py.exp diff --git a/tests/net_hosted/connect_poll.py b/tests/net_hosted/connect_poll.py new file mode 100644 index 0000000000..ece6aa0da9 --- /dev/null +++ b/tests/net_hosted/connect_poll.py @@ -0,0 +1,32 @@ +# test that socket.connect() has correct polling behaviour before, during and after + +try: + import usocket as socket, uselect as select +except: + import socket, select + + +def test(peer_addr): + s = socket.socket() + poller = select.poll() + poller.register(s) + + # test poll before connect + # note: CPython can return POLLHUP, so use the IN|OUT mask + p = poller.poll(0) + print(len(p), p[0][-1] & (select.POLLIN | select.POLLOUT)) + + s.connect(peer_addr) + + # test poll during connection + print(len(poller.poll(0))) + + # test poll after connection is established + p = poller.poll(1000) + print(len(p), p[0][-1]) + + s.close() + + +if __name__ == "__main__": + test(socket.getaddrinfo('micropython.org', 80)[0][-1]) diff --git a/tests/net_hosted/connect_poll.py.exp b/tests/net_hosted/connect_poll.py.exp new file mode 100644 index 0000000000..cdf520e090 --- /dev/null +++ b/tests/net_hosted/connect_poll.py.exp @@ -0,0 +1,3 @@ +1 4 +1 +1 4 From ec1e9a10a73d9c5c3771a5797e9eceb62475b197 Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Sun, 12 Nov 2017 06:13:45 +0000 Subject: [PATCH 041/828] docs: Add notes on heap allocation caused by bound method refs. --- docs/library/micropython.rst | 11 ++++++++++- docs/reference/isr_rules.rst | 29 +++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/docs/library/micropython.rst b/docs/library/micropython.rst index c13a7391bb..d1f923e31f 100644 --- a/docs/library/micropython.rst +++ b/docs/library/micropython.rst @@ -112,5 +112,14 @@ Functions the heap may be locked) and scheduling a function to call later will lift those restrictions. - There is a finite stack to hold the scheduled functions and `schedule` + Note: If `schedule()` is called from a preempting IRQ, when memory + allocation is not allowed and the callback to be passed to `schedule()` is + a bound method, passing this directly will fail. This is because creating a + reference to a bound method causes memory allocation. A solution is to + create a reference to the method in the class constructor and to pass that + reference to `schedule()`. This is discussed in detail here + :ref:`reference documentation ` under "Creation of Python + objects". + + There is a finite stack to hold the scheduled functions and `schedule()` will raise a `RuntimeError` if the stack is full. diff --git a/docs/reference/isr_rules.rst b/docs/reference/isr_rules.rst index 2db261c09d..dfdee048c1 100644 --- a/docs/reference/isr_rules.rst +++ b/docs/reference/isr_rules.rst @@ -124,6 +124,32 @@ A means of creating an object without employing a class or globals is as follows The compiler instantiates the default ``buf`` argument when the function is loaded for the first time (usually when the module it's in is imported). +An instance of object creation occurs when a reference to a bound method is +created. This means that an ISR cannot pass a bound method to a function. One +solution is to create a reference to the bound method in the class constructor +and to pass that reference in the ISR. For example: + +.. code:: python + + class Foo(): + def __init__(self): + self.bar_ref = self.bar # Allocation occurs here + self.x = 0.1 + tim = pyb.Timer(4) + tim.init(freq=2) + tim.callback(self.cb) + + def bar(self, _): + self.x *= 1.2 + print(self.x) + + def cb(self, t): + # Passing self.bar would cause allocation. + micropython.schedule(self.bar_ref, 0) + +Other techniques are to define and instantiate the method in the constructor +or to pass :meth:`Foo.bar` with the argument *self*. + Use of Python objects ~~~~~~~~~~~~~~~~~~~~~ @@ -179,6 +205,9 @@ interrupt occurs while the previous callback is executing, a further instance of for execution; this will run after the current instance has completed. A sustained high interrupt repetition rate therefore carries a risk of unconstrained queue growth and eventual failure with a ``RuntimeError``. +If the callback to be passed to `schedule()` is a bound method, consider the +note in "Creation of Python objects". + Exceptions ---------- From 067bf849d29ab46319740a10561a112376415f51 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 23 Nov 2017 18:03:32 +0200 Subject: [PATCH 042/828] docs/uselect: poll: Explicitly specify that no-timeout value is -1. --- docs/library/uselect.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/library/uselect.rst b/docs/library/uselect.rst index beffce69ae..b9e5da9997 100644 --- a/docs/library/uselect.rst +++ b/docs/library/uselect.rst @@ -50,10 +50,11 @@ Methods Modify the *eventmask* for *obj*. -.. method:: poll.poll([timeout]) +.. method:: poll.poll(timeout=-1) - Wait for at least one of the registered objects to become ready. Returns - list of (``obj``, ``event``, ...) tuples, ``event`` element specifies + Wait for at least one of the registered objects to become ready, with optional + timeout in milliseconds (if *timeout* arg is not specified or -1, there is no + timeout). Returns list of (``obj``, ``event``, ...) tuples, ``event`` element specifies which events happened with a stream and is a combination of ``select.POLL*`` constants described above. There may be other elements in tuple, depending on a platform and version, so don't assume that its size is 2. In case of From 9783ac282ebe216d37be39fdf07113e6880c19b7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 24 Nov 2017 12:07:12 +1100 Subject: [PATCH 043/828] py/runtime: Simplify handling of containment binary operator. In mp_binary_op, there is no need to explicitly check for type->getiter being non-null and raising an exception because this is handled exactly by mp_getiter(). So just call the latter unconditionally. --- py/runtime.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/py/runtime.c b/py/runtime.c index 17e5d235c9..08a35c2e60 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -536,25 +536,17 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { return res; } } - if (type->getiter != NULL) { - /* second attempt, walk the iterator */ - mp_obj_iter_buf_t iter_buf; - mp_obj_t iter = mp_getiter(rhs, &iter_buf); - mp_obj_t next; - while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { - if (mp_obj_equal(next, lhs)) { - return mp_const_true; - } - } - return mp_const_false; - } - if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("object not iterable"); - } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, - "'%s' object is not iterable", mp_obj_get_type_str(rhs))); + // final attempt, walk the iterator (will raise if rhs is not iterable) + mp_obj_iter_buf_t iter_buf; + mp_obj_t iter = mp_getiter(rhs, &iter_buf); + mp_obj_t next; + while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { + if (mp_obj_equal(next, lhs)) { + return mp_const_true; + } } + return mp_const_false; } // generic binary_op supplied by type From 5b2f62aff312949c9c7edec6cfaaf4f97d93c442 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 24 Nov 2017 12:16:21 +1100 Subject: [PATCH 044/828] py/opmethods: Include the correct header for binary op enums. By directly including runtime0.h the mpconfig.h settings are not included and so the enums in runtime0.h can be incorrect. --- py/opmethods.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/opmethods.c b/py/opmethods.c index 1200ba39ef..31901bb521 100644 --- a/py/opmethods.c +++ b/py/opmethods.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include "py/runtime0.h" +#include "py/obj.h" #include "py/builtin.h" STATIC mp_obj_t op_getitem(mp_obj_t self_in, mp_obj_t key_in) { From 5e34a113eaaf736fb4f703a3ee0892e1705d0a63 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 24 Nov 2017 13:04:24 +1100 Subject: [PATCH 045/828] py/runtime: Add MP_BINARY_OP_CONTAINS as reverse of MP_BINARY_OP_IN. Before this patch MP_BINARY_OP_IN had two meanings: coming from bytecode it meant that the args needed to be swapped, but coming from within the runtime meant that the args were already in the correct order. This lead to some confusion in the code and comments stating how args were reversed. It also lead to 2 bugs: 1) containment for a subclass of a native type didn't work; 2) the expression "{True} in True" would illegally succeed and return True. In both of these cases it was because the args to MP_BINARY_OP_IN ended up being reversed twice. To fix these things this patch introduces MP_BINARY_OP_CONTAINS which corresponds exactly to the __contains__ special method, and this is the operator that built-in types should implement. MP_BINARY_OP_IN is now only emitted by the compiler and is converted to MP_BINARY_OP_CONTAINS by swapping the arguments. --- extmod/modbtree.c | 2 +- py/objarray.c | 3 +- py/objdict.c | 4 +-- py/objint_mpz.c | 2 +- py/objset.c | 4 +-- py/objstr.c | 3 +- py/objtype.c | 2 +- py/opmethods.c | 2 +- py/runtime.c | 42 +++++++++++++--------------- py/runtime0.h | 4 +++ tests/micropython/viper_error.py.exp | 2 +- 11 files changed, 34 insertions(+), 36 deletions(-) diff --git a/extmod/modbtree.c b/extmod/modbtree.c index 5c13115328..8b76885809 100644 --- a/extmod/modbtree.c +++ b/extmod/modbtree.c @@ -282,7 +282,7 @@ STATIC mp_obj_t btree_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { STATIC mp_obj_t btree_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { mp_obj_btree_t *self = MP_OBJ_TO_PTR(lhs_in); switch (op) { - case MP_BINARY_OP_IN: { + case MP_BINARY_OP_CONTAINS: { DBT key, val; key.data = (void*)mp_obj_str_get_data(rhs_in, &key.size); int res = __bt_get(self->db, &key, &val, 0); diff --git a/py/objarray.c b/py/objarray.c index 7003ec9e7d..a35539484b 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -269,8 +269,7 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs return lhs_in; } - case MP_BINARY_OP_IN: { - /* NOTE `a in b` is `b.__contains__(a)` */ + case MP_BINARY_OP_CONTAINS: { mp_buffer_info_t lhs_bufinfo; mp_buffer_info_t rhs_bufinfo; diff --git a/py/objdict.c b/py/objdict.c index 1553a83b46..d0f95e41ad 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -115,7 +115,7 @@ STATIC mp_obj_t dict_unary_op(mp_unary_op_t op, mp_obj_t self_in) { STATIC mp_obj_t dict_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { mp_obj_dict_t *o = MP_OBJ_TO_PTR(lhs_in); switch (op) { - case MP_BINARY_OP_IN: { + case MP_BINARY_OP_CONTAINS: { mp_map_elem_t *elem = mp_map_lookup(&o->map, rhs_in, MP_MAP_LOOKUP); return mp_obj_new_bool(elem != NULL); } @@ -485,7 +485,7 @@ STATIC mp_obj_t dict_view_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t if (o->kind != MP_DICT_VIEW_KEYS) { return MP_OBJ_NULL; // op not supported } - if (op != MP_BINARY_OP_IN) { + if (op != MP_BINARY_OP_CONTAINS) { return MP_OBJ_NULL; // op not supported } return dict_binary_op(op, o->dict, rhs_in); diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 7b5cb0b9d4..17e3ee6d24 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -207,7 +207,7 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i return mp_obj_new_float(flhs / frhs); #endif - } else if (op >= MP_BINARY_OP_INPLACE_OR) { + } else if (op >= MP_BINARY_OP_INPLACE_OR && op < MP_BINARY_OP_CONTAINS) { mp_obj_int_t *res = mp_obj_int_new_mpz(); switch (op) { diff --git a/py/objset.c b/py/objset.c index 6ed15c7914..3e98c30e8f 100644 --- a/py/objset.c +++ b/py/objset.c @@ -461,7 +461,7 @@ STATIC mp_obj_t set_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { #else bool update = true; #endif - if (op != MP_BINARY_OP_IN && !is_set_or_frozenset(rhs)) { + if (op != MP_BINARY_OP_CONTAINS && !is_set_or_frozenset(rhs)) { // For all ops except containment the RHS must be a set/frozenset return MP_OBJ_NULL; } @@ -507,7 +507,7 @@ STATIC mp_obj_t set_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { return set_issubset(lhs, rhs); case MP_BINARY_OP_MORE_EQUAL: return set_issuperset(lhs, rhs); - case MP_BINARY_OP_IN: { + case MP_BINARY_OP_CONTAINS: { mp_obj_set_t *o = MP_OBJ_TO_PTR(lhs); mp_obj_t elem = mp_set_lookup(&o->set, rhs, MP_MAP_LOOKUP); return mp_obj_new_bool(elem != MP_OBJ_NULL); diff --git a/py/objstr.c b/py/objstr.c index 1ff5132d29..b4f15b38d5 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -384,8 +384,7 @@ mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i return mp_obj_new_str_from_vstr(lhs_type, &vstr); } - case MP_BINARY_OP_IN: - /* NOTE `a in b` is `b.__contains__(a)` */ + case MP_BINARY_OP_CONTAINS: return mp_obj_new_bool(find_subbytes(lhs_data, lhs_len, rhs_data, rhs_len, 1) != NULL); //case MP_BINARY_OP_NOT_EQUAL: // This is never passed here diff --git a/py/objtype.c b/py/objtype.c index 01d248256a..267cae8156 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -424,7 +424,7 @@ const byte mp_binary_op_method_name[MP_BINARY_OP_NUM_RUNTIME] = { [MP_BINARY_OP_LESS_EQUAL] = MP_QSTR___le__, [MP_BINARY_OP_MORE_EQUAL] = MP_QSTR___ge__, // MP_BINARY_OP_NOT_EQUAL, // a != b calls a == b and inverts result - [MP_BINARY_OP_IN] = MP_QSTR___contains__, + [MP_BINARY_OP_CONTAINS] = MP_QSTR___contains__, // All inplace methods are optional, and normal methods will be used // as a fallback. diff --git a/py/opmethods.c b/py/opmethods.c index 31901bb521..247fa5bbc8 100644 --- a/py/opmethods.c +++ b/py/opmethods.c @@ -47,6 +47,6 @@ MP_DEFINE_CONST_FUN_OBJ_2(mp_op_delitem_obj, op_delitem); STATIC mp_obj_t op_contains(mp_obj_t lhs_in, mp_obj_t rhs_in) { mp_obj_type_t *type = mp_obj_get_type(lhs_in); - return type->binary_op(MP_BINARY_OP_IN, lhs_in, rhs_in); + return type->binary_op(MP_BINARY_OP_CONTAINS, lhs_in, rhs_in); } MP_DEFINE_CONST_FUN_OBJ_2(mp_op_contains_obj, op_contains); diff --git a/py/runtime.c b/py/runtime.c index 08a35c2e60..c7fe393675 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -523,30 +523,12 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { } } - /* deal with `in` - * - * NOTE `a in b` is `b.__contains__(a)`, hence why the generic dispatch - * needs to go below with swapped arguments - */ + // Convert MP_BINARY_OP_IN to MP_BINARY_OP_CONTAINS with swapped args. if (op == MP_BINARY_OP_IN) { - mp_obj_type_t *type = mp_obj_get_type(rhs); - if (type->binary_op != NULL) { - mp_obj_t res = type->binary_op(op, rhs, lhs); - if (res != MP_OBJ_NULL) { - return res; - } - } - - // final attempt, walk the iterator (will raise if rhs is not iterable) - mp_obj_iter_buf_t iter_buf; - mp_obj_t iter = mp_getiter(rhs, &iter_buf); - mp_obj_t next; - while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { - if (mp_obj_equal(next, lhs)) { - return mp_const_true; - } - } - return mp_const_false; + op = MP_BINARY_OP_CONTAINS; + mp_obj_t temp = lhs; + lhs = rhs; + rhs = temp; } // generic binary_op supplied by type @@ -575,6 +557,20 @@ generic_binary_op: } #endif + if (op == MP_BINARY_OP_CONTAINS) { + // If type didn't support containment then explicitly walk the iterator. + // mp_getiter will raise the appropriate exception if lhs is not iterable. + mp_obj_iter_buf_t iter_buf; + mp_obj_t iter = mp_getiter(lhs, &iter_buf); + mp_obj_t next; + while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { + if (mp_obj_equal(next, rhs)) { + return mp_const_true; + } + } + return mp_const_false; + } + unsupported_op: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("unsupported type for operator"); diff --git a/py/runtime0.h b/py/runtime0.h index a72b7feb7a..960532d176 100644 --- a/py/runtime0.h +++ b/py/runtime0.h @@ -131,6 +131,10 @@ typedef enum { #endif , + // The runtime will convert MP_BINARY_OP_IN to this operator with swapped args. + // A type should implement this containment operator instead of MP_BINARY_OP_IN. + MP_BINARY_OP_CONTAINS, + MP_BINARY_OP_NUM_RUNTIME, // These 2 are not supported by the runtime and must be synthesised by the emitter diff --git a/tests/micropython/viper_error.py.exp b/tests/micropython/viper_error.py.exp index 96be5a5902..a44fb3ff0a 100644 --- a/tests/micropython/viper_error.py.exp +++ b/tests/micropython/viper_error.py.exp @@ -18,7 +18,7 @@ ViperTypeError('must raise an object',) ViperTypeError('unary op __pos__ not implemented',) ViperTypeError('unary op __neg__ not implemented',) ViperTypeError('unary op __invert__ not implemented',) -ViperTypeError('binary op __contains__ not implemented',) +ViperTypeError('binary op not implemented',) NotImplementedError('native yield',) NotImplementedError('native yield from',) NotImplementedError('conversion to object',) From 505671b698490918fe0ea6c6dfdab8c0b25339be Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 24 Nov 2017 14:48:41 +1100 Subject: [PATCH 046/828] tests/basics: Add test for containment of a subclass of a native type. --- tests/basics/subclass_native_containment.py | 22 +++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/basics/subclass_native_containment.py diff --git a/tests/basics/subclass_native_containment.py b/tests/basics/subclass_native_containment.py new file mode 100644 index 0000000000..7400f7583e --- /dev/null +++ b/tests/basics/subclass_native_containment.py @@ -0,0 +1,22 @@ +# test containment operator on subclass of a native type + +class mylist(list): + pass + +class mydict(dict): + pass + +class mybytes(bytes): + pass + +l = mylist([1, 2, 3]) +print(0 in l) +print(1 in l) + +d = mydict({1:1, 2:2}) +print(0 in l) +print(1 in l) + +b = mybytes(b'1234') +print(0 in b) +print(b'1' in b) From c7a0e1472da8e1b8e359bc26f838ab20bab00a8a Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 24 Nov 2017 15:30:12 +1100 Subject: [PATCH 047/828] tests/basics/builtin_range: Add test for corner case of range slicing. --- tests/basics/builtin_range.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/basics/builtin_range.py b/tests/basics/builtin_range.py index 0e2fabd82e..66226bad16 100644 --- a/tests/basics/builtin_range.py +++ b/tests/basics/builtin_range.py @@ -38,6 +38,9 @@ print(range(1, 100, 5)[15:5:-3]) print(range(100, 1, -5)[5:15:3]) print(range(100, 1, -5)[15:5:-3]) +# for this case uPy gives a different stop value but the listed elements are still correct +print(list(range(7, -2, -4)[2:-2:])) + # zero step try: range(1, 2, 0) From e511f24ddd62f8157ac137f8e4b87e15e5012d70 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 30 Oct 2017 12:48:14 +1100 Subject: [PATCH 048/828] extmod/modussl_axtls: Implement key and cert kw args to wrap_socket. The key and cert must both be a str/bytes object in DER format. --- extmod/modussl_axtls.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/extmod/modussl_axtls.c b/extmod/modussl_axtls.c index 4d8440a89c..35e3106cdb 100644 --- a/extmod/modussl_axtls.c +++ b/extmod/modussl_axtls.c @@ -44,6 +44,8 @@ typedef struct _mp_obj_ssl_socket_t { } mp_obj_ssl_socket_t; struct ssl_args { + mp_arg_val_t key; + mp_arg_val_t cert; mp_arg_val_t server_side; mp_arg_val_t server_hostname; }; @@ -62,10 +64,28 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { o->sock = sock; uint32_t options = SSL_SERVER_VERIFY_LATER; + if (args->key.u_obj != mp_const_none) { + options |= SSL_NO_DEFAULT_KEY; + } if ((o->ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS)) == NULL) { mp_raise_OSError(MP_EINVAL); } + if (args->key.u_obj != mp_const_none) { + size_t len; + const byte *data = (const byte*)mp_obj_str_get_data(args->key.u_obj, &len); + int res = ssl_obj_memory_load(o->ssl_ctx, SSL_OBJ_RSA_KEY, data, len, NULL); + if (res != SSL_OK) { + mp_raise_ValueError("invalid key"); + } + + data = (const byte*)mp_obj_str_get_data(args->cert.u_obj, &len); + res = ssl_obj_memory_load(o->ssl_ctx, SSL_OBJ_X509_CERT, data, len, NULL); + if (res != SSL_OK) { + mp_raise_ValueError("invalid cert"); + } + } + if (args->server_side.u_bool) { o->ssl_sock = ssl_server_new(o->ssl_ctx, (long)sock); } else { @@ -211,6 +231,8 @@ STATIC const mp_obj_type_t ussl_socket_type = { STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { // TODO: Implement more args static const mp_arg_t allowed_args[] = { + { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; From 48f6990fbc54ac29b15fa765d431244d1dcb5f21 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 31 Oct 2017 13:50:08 +1100 Subject: [PATCH 049/828] extmod/modlwip: Commit TCP out data to lower layers if buffer gets full. Dramatically improves TCP sending throughput because without an explicit call to tcp_output() the data is only sent to the lower layers via the lwIP slow timer which (by default) ticks every 500ms. --- extmod/modlwip.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index bbb01b5d76..2c194e1bd8 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -498,6 +498,11 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui err_t err = tcp_write(socket->pcb.tcp, buf, write_len, TCP_WRITE_FLAG_COPY); + // If the output buffer is getting full then send the data to the lower layers + if (err == ERR_OK && tcp_sndbuf(socket->pcb.tcp) < TCP_SND_BUF / 4) { + err = tcp_output(socket->pcb.tcp); + } + if (err != ERR_OK) { *_errno = error_lookup_table[-err]; return MP_STREAM_ERROR; From c23cc4cc81a3e437528d8c94e55bfe58db87ea86 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 26 Oct 2017 23:09:17 +0300 Subject: [PATCH 050/828] docs/uctypes: Typo/article fixes. --- docs/library/uctypes.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/library/uctypes.rst b/docs/library/uctypes.rst index 2a9c4dd5c0..164e0eb9d7 100644 --- a/docs/library/uctypes.rst +++ b/docs/library/uctypes.rst @@ -8,7 +8,7 @@ This module implements "foreign data interface" for MicroPython. The idea behind it is similar to CPython's ``ctypes`` modules, but the actual API is different, streamlined and optimized for small size. The basic idea of the module is to define data structure layout with about the same power as the -C language allows, and the access it using familiar dot-syntax to reference +C language allows, and then access it using familiar dot-syntax to reference sub-fields. .. seealso:: @@ -43,7 +43,7 @@ Following are encoding examples for various field types: i.e. value is a 2-tuple, first element of which is offset, and second is a structure descriptor dictionary (note: offsets in recursive descriptors - are relative to a structure it defines). + are relative to the structure it defines). * Arrays of primitive types:: @@ -86,9 +86,9 @@ Following are encoding examples for various field types: BF_POS and BF_LEN positions, respectively. Bitfield position is counted from the least significant bit, and is the number of right-most bit of a field (in other words, it's a number of bits a scalar needs to be shifted - right to extra the bitfield). + right to extract the bitfield). - In the example above, first UINT16 value will be extracted at offset 0 + In the example above, first a UINT16 value will be extracted at offset 0 (this detail may be important when accessing hardware registers, where particular access size and alignment are required), and then bitfield whose rightmost bit is least-significant bit of this UINT16, and length @@ -99,7 +99,7 @@ Following are encoding examples for various field types: in particular, example above will access least-significant byte of UINT16 in both little- and big-endian structures. But it depends on the least significant bit being numbered 0. Some targets may use different - numbering in their native ABI, but ``uctypes`` always uses normalized + numbering in their native ABI, but ``uctypes`` always uses the normalized numbering described above. Module contents From 50cffcfe2c479fac9d815cfb28c19e1854070d56 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 26 Oct 2017 23:11:09 +0300 Subject: [PATCH 051/828] docs/uctypes: Tweak descriptor reference to hopefully be easier to follow. Put offset first in OR expressions, and use "offset" var instead of hardcoded numbers. Hopefully, this will make it more self-describing and show patterns better. --- docs/library/uctypes.rst | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/docs/library/uctypes.rst b/docs/library/uctypes.rst index 164e0eb9d7..c938d74a8e 100644 --- a/docs/library/uctypes.rst +++ b/docs/library/uctypes.rst @@ -29,16 +29,16 @@ Following are encoding examples for various field types: * Scalar types:: - "field_name": uctypes.UINT32 | 0 + "field_name": offset | uctypes.UINT32 in other words, value is scalar type identifier ORed with field offset (in bytes) from the start of the structure. * Recursive structures:: - "sub": (2, { - "b0": uctypes.UINT8 | 0, - "b1": uctypes.UINT8 | 1, + "sub": (offset, { + "b0": 0 | uctypes.UINT8, + "b1": 1 | uctypes.UINT8, }) i.e. value is a 2-tuple, first element of which is offset, and second is @@ -47,7 +47,7 @@ Following are encoding examples for various field types: * Arrays of primitive types:: - "arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 2), + "arr": (offset | uctypes.ARRAY, size | uctypes.UINT8), i.e. value is a 2-tuple, first element of which is ARRAY flag ORed with offset, and second is scalar element type ORed number of elements @@ -55,7 +55,7 @@ Following are encoding examples for various field types: * Arrays of aggregate types:: - "arr2": (uctypes.ARRAY | 0, 2, {"b": uctypes.UINT8 | 0}), + "arr2": (offset | uctypes.ARRAY, size, {"b": 0 | uctypes.UINT8}), i.e. value is a 3-tuple, first element of which is ARRAY flag ORed with offset, second is a number of elements in array, and third is @@ -63,21 +63,21 @@ Following are encoding examples for various field types: * Pointer to a primitive type:: - "ptr": (uctypes.PTR | 0, uctypes.UINT8), + "ptr": (offset | uctypes.PTR, uctypes.UINT8), i.e. value is a 2-tuple, first element of which is PTR flag ORed with offset, and second is scalar element type. * Pointer to an aggregate type:: - "ptr2": (uctypes.PTR | 0, {"b": uctypes.UINT8 | 0}), + "ptr2": (offset | uctypes.PTR, {"b": 0 | uctypes.UINT8}), i.e. value is a 2-tuple, first element of which is PTR flag ORed with offset, second is descriptor of type pointed to. * Bitfields:: - "bitf0": uctypes.BFUINT16 | 0 | 0 << uctypes.BF_POS | 8 << uctypes.BF_LEN, + "bitf0": offset | uctypes.BFUINT16 | lsbit << uctypes.BF_POS | bitsize << uctypes.BF_LEN, i.e. value is type of scalar value containing given bitfield (typenames are similar to scalar types, but prefixes with "BF"), ORed with offset for @@ -91,9 +91,10 @@ Following are encoding examples for various field types: In the example above, first a UINT16 value will be extracted at offset 0 (this detail may be important when accessing hardware registers, where particular access size and alignment are required), and then bitfield - whose rightmost bit is least-significant bit of this UINT16, and length - is 8 bits, will be extracted - effectively, this will access - least-significant byte of UINT16. + whose rightmost bit is *lsbit* bit of this UINT16, and length + is *bitsize* bits, will be extracted. For example, if *lsbit* is 0 and + *bitsize* is 8, then effectively it will access least-significant byte + of UINT16. Note that bitfield operations are independent of target byte endianness, in particular, example above will access least-significant byte of UINT16 From f59c6b48aed765fc0eb3785686ffb11f2efc8eae Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 26 Nov 2017 09:55:02 +0200 Subject: [PATCH 052/828] docs/uselect: Describe POLLHUP/POLLERR semantics in more details. Per POSIX, http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html these flags aren't valid in the input eventmask. Instead, they can be returned in unsolicited manner in the output eventmask at any time. --- docs/library/uselect.rst | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/docs/library/uselect.rst b/docs/library/uselect.rst index b9e5da9997..aa70bec690 100644 --- a/docs/library/uselect.rst +++ b/docs/library/uselect.rst @@ -35,12 +35,15 @@ Methods Register *obj* for polling. *eventmask* is logical OR of: - * ``select.POLLIN`` - data available for reading - * ``select.POLLOUT`` - more data can be written - * ``select.POLLERR`` - error occurred - * ``select.POLLHUP`` - end of stream/connection termination detected + * `uselect.POLLIN` - data available for reading + * `uselect.POLLOUT` - more data can be written - *eventmask* defaults to ``select.POLLIN | select.POLLOUT``. + Note that flags like `uselect.POLLHUP` and `uselect.POLLERR` are + *not* valid as input eventmask (these are unsolicited events which + will be returned from `poll()` regardless of whether they are asked + for). This semantics is per POSIX. + + *eventmask* defaults to ``uselect.POLLIN | uselect.POLLOUT``. .. method:: poll.unregister(obj) @@ -52,15 +55,21 @@ Methods .. method:: poll.poll(timeout=-1) - Wait for at least one of the registered objects to become ready, with optional - timeout in milliseconds (if *timeout* arg is not specified or -1, there is no - timeout). Returns list of (``obj``, ``event``, ...) tuples, ``event`` element specifies - which events happened with a stream and is a combination of ``select.POLL*`` - constants described above. There may be other elements in tuple, depending - on a platform and version, so don't assume that its size is 2. In case of - timeout, an empty list is returned. + Wait for at least one of the registered objects to become ready or have an + exceptional condition, with optional timeout in milliseconds (if *timeout* + arg is not specified or -1, there is no timeout). - Timeout is in milliseconds. + Returns list of (``obj``, ``event``, ...) tuples. There may be other elements in + tuple, depending on a platform and version, so don't assume that its size is 2. + The ``event`` element specifies which events happened with a stream and + is a combination of ``uselect.POLL*`` constants described above. Note that + flags `uselect.POLLHUP` and `uselect.POLLERR` can be returned at any time + (even if were not asked for), and must be acted on accordingly (the + corresponding stream unregistered from poll and likely closed), because + otherwise all further invocations of `poll()` may return immediately with + these flags set for this stream again. + + In case of timeout, an empty list is returned. .. admonition:: Difference to CPython :class: attention From 84895f1a210d0037a86887f0f647570bdf40afa2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 27 Nov 2017 12:51:52 +1100 Subject: [PATCH 053/828] py/parsenum: Improve parsing of floating point numbers. This patch improves parsing of floating point numbers by converting all the digits (integer and fractional) together into a number 1 or greater, and then applying the correct power of 10 at the very end. In particular the multiple "multiply by 0.1" operations to build a fraction are now combined together and applied at the same time as the exponent, at the very end. This helps to retain precision during parsing of floats, and also includes a check that the number doesn't overflow during the parsing. One benefit is that a float will have the same value no matter where the decimal point is located, eg 1.23 == 123e-2. --- py/parsenum.c | 27 +++++++++++++++++++++------ tests/float/float_parse.py | 22 ++++++++++++++++++++++ tests/float/float_parse_doubleprec.py | 16 ++++++++++++++++ tests/run-tests | 1 + 4 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 tests/float/float_parse.py create mode 100644 tests/float/float_parse_doubleprec.py diff --git a/py/parsenum.c b/py/parsenum.c index b62029f7c7..98e7736851 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -170,6 +170,14 @@ typedef enum { mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool force_complex, mp_lexer_t *lex) { #if MICROPY_PY_BUILTINS_FLOAT + +// DEC_VAL_MAX only needs to be rough and is used to retain precision while not overflowing +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +#define DEC_VAL_MAX 1e20F +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +#define DEC_VAL_MAX 1e200 +#endif + const char *top = str + len; mp_float_t dec_val = 0; bool dec_neg = false; @@ -214,8 +222,8 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool // string should be a decimal number parse_dec_in_t in = PARSE_DEC_IN_INTG; bool exp_neg = false; - mp_float_t frac_mult = 0.1; mp_int_t exp_val = 0; + mp_int_t exp_extra = 0; while (str < top) { mp_uint_t dig = *str++; if ('0' <= dig && dig <= '9') { @@ -223,11 +231,18 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool if (in == PARSE_DEC_IN_EXP) { exp_val = 10 * exp_val + dig; } else { - if (in == PARSE_DEC_IN_FRAC) { - dec_val += dig * frac_mult; - frac_mult *= MICROPY_FLOAT_CONST(0.1); - } else { + if (dec_val < DEC_VAL_MAX) { + // dec_val won't overflow so keep accumulating dec_val = 10 * dec_val + dig; + if (in == PARSE_DEC_IN_FRAC) { + --exp_extra; + } + } else { + // dec_val might overflow and we anyway can't represent more digits + // of precision, so ignore the digit and just adjust the exponent + if (in == PARSE_DEC_IN_INTG) { + ++exp_extra; + } } } } else if (in == PARSE_DEC_IN_INTG && dig == '.') { @@ -261,7 +276,7 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool } // apply the exponent - dec_val *= MICROPY_FLOAT_C_FUN(pow)(10, exp_val); + dec_val *= MICROPY_FLOAT_C_FUN(pow)(10, exp_val + exp_extra); } // negate value if needed diff --git a/tests/float/float_parse.py b/tests/float/float_parse.py new file mode 100644 index 0000000000..448eff3bc9 --- /dev/null +++ b/tests/float/float_parse.py @@ -0,0 +1,22 @@ +# test parsing of floats + +inf = float('inf') + +# it shouldn't matter where the decimal point is if the exponent balances the value +print(float('1234') - float('0.1234e4')) +print(float('1.015625') - float('1015625e-6')) + +# very large integer part with a very negative exponent should cancel out +print(float('9' * 60 + 'e-60')) +print(float('9' * 60 + 'e-40')) +print(float('9' * 60 + 'e-20') == float('1e40')) + +# many fractional digits +print(float('.' + '9' * 70)) +print(float('.' + '9' * 70 + 'e20')) +print(float('.' + '9' * 70 + 'e-50') == float('1e-50')) + +# tiny fraction with large exponent +print(float('.' + '0' * 60 + '1e10') == float('1e-51')) +print(float('.' + '0' * 60 + '9e25')) +print(float('.' + '0' * 60 + '9e40')) diff --git a/tests/float/float_parse_doubleprec.py b/tests/float/float_parse_doubleprec.py new file mode 100644 index 0000000000..3566011309 --- /dev/null +++ b/tests/float/float_parse_doubleprec.py @@ -0,0 +1,16 @@ +# test parsing of floats, requiring double-precision + +# very large integer part with a very negative exponent should cancel out +print(float('9' * 400 + 'e-100')) +print(float('9' * 400 + 'e-200')) +print(float('9' * 400 + 'e-400')) + +# many fractional digits +print(float('.' + '9' * 400)) +print(float('.' + '9' * 400 + 'e100')) +print(float('.' + '9' * 400 + 'e-100')) + +# tiny fraction with large exponent +print(float('.' + '0' * 400 + '9e100')) +print(float('.' + '0' * 400 + '9e200')) +print(float('.' + '0' * 400 + '9e400')) diff --git a/tests/run-tests b/tests/run-tests index 6280a5182b..3c763512c0 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -271,6 +271,7 @@ def run_tests(pyb, tests, args, base_path="."): if upy_float_precision < 64: skip_tests.add('float/float_divmod.py') # tested by float/float_divmod_relaxed.py instead skip_tests.add('float/float2int_doubleprec_intbig.py') + skip_tests.add('float/float_parse_doubleprec.py') if not has_complex: skip_tests.add('float/complex1.py') From c3bc8d7b2b372abf154aeddf762f5e2b859a0e5b Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 27 Nov 2017 14:14:57 +1100 Subject: [PATCH 054/828] tests/basics/builtin_locals: Add test for using locals() in class body. --- tests/basics/builtin_locals.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/basics/builtin_locals.py b/tests/basics/builtin_locals.py index 3689216ef6..e60759a40e 100644 --- a/tests/basics/builtin_locals.py +++ b/tests/basics/builtin_locals.py @@ -2,3 +2,12 @@ x = 123 print(locals()['x']) + +class A: + y = 1 + def f(self): + pass + + print('x' in locals()) + print(locals()['y']) + print('f' in locals()) From 2161d6b603e2dfc444a597c4346f7e2301f9c05e Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 27 Nov 2017 23:40:31 +1100 Subject: [PATCH 055/828] py/objdict: Reuse dict-view key iterator for standard dict iterator. It has equivalent behaviour and reusing it saves some code bytes. --- py/objdict.c | 45 ++++++++++++++------------------------------- 1 file changed, 14 insertions(+), 31 deletions(-) diff --git a/py/objdict.c b/py/objdict.c index d0f95e41ad..f6fb594b3c 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -192,37 +192,6 @@ STATIC mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { } } -/******************************************************************************/ -/* dict iterator */ - -typedef struct _mp_obj_dict_it_t { - mp_obj_base_t base; - mp_fun_1_t iternext; - mp_obj_t dict; - size_t cur; -} mp_obj_dict_it_t; - -STATIC mp_obj_t dict_it_iternext(mp_obj_t self_in) { - mp_obj_dict_it_t *self = MP_OBJ_TO_PTR(self_in); - mp_map_elem_t *next = dict_iter_next(MP_OBJ_TO_PTR(self->dict), &self->cur); - - if (next == NULL) { - return MP_OBJ_STOP_ITERATION; - } else { - return next->key; - } -} - -STATIC mp_obj_t dict_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { - assert(sizeof(mp_obj_dict_it_t) <= sizeof(mp_obj_iter_buf_t)); - mp_obj_dict_it_t *o = (mp_obj_dict_it_t*)iter_buf; - o->base.type = &mp_type_polymorph_iter; - o->iternext = dict_it_iternext; - o->dict = self_in; - o->cur = 0; - return MP_OBJ_FROM_PTR(o); -} - /******************************************************************************/ /* dict methods */ @@ -527,6 +496,20 @@ STATIC mp_obj_t dict_values(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_values_obj, dict_values); +/******************************************************************************/ +/* dict iterator */ + +STATIC mp_obj_t dict_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { + assert(sizeof(mp_obj_dict_view_it_t) <= sizeof(mp_obj_iter_buf_t)); + mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_obj_dict_view_it_t *o = (mp_obj_dict_view_it_t*)iter_buf; + o->base.type = &dict_view_it_type; + o->kind = MP_DICT_VIEW_KEYS; + o->dict = self_in; + o->cur = 0; + return MP_OBJ_FROM_PTR(o); +} + /******************************************************************************/ /* dict constructors & public C API */ From 7cf446f3daa820b15f0027d3468f1b78be17fec7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 28 Nov 2017 10:50:32 +1100 Subject: [PATCH 056/828] tools/gen-cpydiff.py: Update executable paths to point to new ports dir. --- tools/gen-cpydiff.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/gen-cpydiff.py b/tools/gen-cpydiff.py index aff5b56e7b..8aef375149 100644 --- a/tools/gen-cpydiff.py +++ b/tools/gen-cpydiff.py @@ -39,10 +39,10 @@ from collections import namedtuple # to the correct executable. if os.name == 'nt': CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3.exe') - MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../windows/micropython.exe') + MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../ports/windows/micropython.exe') else: CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3') - MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../unix/micropython') + MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../ports/unix/micropython') TESTPATH = '../tests/cpydiff/' DOCPATH = '../docs/genrst/' From 63f47104feec03cd529b80c654a2aa80e3e7d524 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 28 Nov 2017 10:50:53 +1100 Subject: [PATCH 057/828] tests/cpydiff: Add difference-test for second arg of builtin next(). --- tests/cpydiff/builtin_next_arg2.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/cpydiff/builtin_next_arg2.py diff --git a/tests/cpydiff/builtin_next_arg2.py b/tests/cpydiff/builtin_next_arg2.py new file mode 100644 index 0000000000..cbde773f90 --- /dev/null +++ b/tests/cpydiff/builtin_next_arg2.py @@ -0,0 +1,12 @@ +""" +categories: Modules,builtins +description: Second argument to next() is not implemented +cause: MicroPython is optimised for code space. +workaround: Instead of `val = next(it, deflt)` use:: + + try: + val = next(it) + except StopIteration: + val = deflt +""" +print(next(iter(range(0)), 42)) From 53e06e05c917ac4a9ee6bff9a7665b2f7439badf Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 28 Nov 2017 13:37:26 +0200 Subject: [PATCH 058/828] zephyr/Makefile: clean: Remove generated prj_*_merged.conf. --- ports/zephyr/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr/Makefile b/ports/zephyr/Makefile index 2e6cb41b98..81aaaa6dc6 100644 --- a/ports/zephyr/Makefile +++ b/ports/zephyr/Makefile @@ -90,7 +90,7 @@ build/genhdr/qstr.i.last: | $(Z_EXPORTS) LIBMICROPYTHON_EXTRA_CMD = -$(RM) -f outdir/$(OUTDIR_PREFIX)/zephyr.lnk # MicroPython's global clean cleans everything, fast -CLEAN_EXTRA = outdir +CLEAN_EXTRA = outdir prj_*_merged.conf # Clean Zephyr things in Zephyr way z_clean: From a289b24e2524b793b6351ba6feb4e0f5ed2516ec Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 28 Nov 2017 13:59:24 +0200 Subject: [PATCH 059/828] tests/run-tests: "minimal": Skip recently added float/float_parse.py. Fails for Zephyr qemu_x86 with: -9e-36 +9.000001e-36 --- tests/run-tests | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-tests b/tests/run-tests index 3c763512c0..a2efede0ae 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -312,6 +312,7 @@ def run_tests(pyb, tests, args, base_path="."): skip_tests.add('basics/class_inplace_op.py') # all special methods not supported skip_tests.add('misc/rge_sm.py') # too large skip_tests.add('micropython/opt_level.py') # don't assume line numbers are stored + skip_tests.add('float/float_parse.py') # minor parsing artifacts with 32-bit floats # Some tests are known to fail on 64-bit machines if pyb is None and platform.architecture()[0] == '64bit': From 25b7c7d7c66e46a9a5729b149ac35ebf13343716 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 28 Nov 2017 14:11:46 +0200 Subject: [PATCH 060/828] zephyr/prj_base.conf: Force zephyr.bin build output. As useful for CI systems. 1.10 doesn't build .bin for qemu_* for example. Also, remove deprecated CONFIG_LEGACY_KERNEL option. --- ports/zephyr/prj_base.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr/prj_base.conf b/ports/zephyr/prj_base.conf index fbcedf2600..58c65f14de 100644 --- a/ports/zephyr/prj_base.conf +++ b/ports/zephyr/prj_base.conf @@ -1,4 +1,4 @@ -CONFIG_LEGACY_KERNEL=n +CONFIG_BUILD_OUTPUT_BIN=y CONFIG_REBOOT=y CONFIG_STDOUT_CONSOLE=y From a036554a77c50fc4aabf056d93f7b3170ee4af21 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 17 Nov 2017 20:23:45 +0200 Subject: [PATCH 061/828] zephyr/Makefile: Convert to new CMake-based Zephyr build system. Zephyr 1.10 switches to CMake-based build system (already in master). --- ports/zephyr/CMakeLists.txt | 21 +++++++++++++++++++++ ports/zephyr/Makefile | 26 +++++++++++++------------- 2 files changed, 34 insertions(+), 13 deletions(-) create mode 100644 ports/zephyr/CMakeLists.txt diff --git a/ports/zephyr/CMakeLists.txt b/ports/zephyr/CMakeLists.txt new file mode 100644 index 0000000000..cd7eda227c --- /dev/null +++ b/ports/zephyr/CMakeLists.txt @@ -0,0 +1,21 @@ +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(NONE) + +target_sources(app PRIVATE src/zephyr_start.c src/zephyr_getchar.c) + +add_library(libmicropython STATIC IMPORTED) +set_target_properties(libmicropython PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/libmicropython.a) +target_link_libraries(app libmicropython) + +zephyr_get_include_directories_as_string(includes) +zephyr_get_system_include_directories_as_string(system_includes) +zephyr_get_compile_definitions_as_string(definitions) +zephyr_get_compile_options_as_string(options) + +add_custom_target( + outputexports + COMMAND echo CC="${CMAKE_C_COMPILER}" + COMMAND echo Z_CFLAGS=${system_includes}${includes}${definitions}${options} + VERBATIM + USES_TERMINAL +) diff --git a/ports/zephyr/Makefile b/ports/zephyr/Makefile index 81aaaa6dc6..ec2bbbcb62 100644 --- a/ports/zephyr/Makefile +++ b/ports/zephyr/Makefile @@ -20,15 +20,15 @@ FROZEN_DIR = scripts # Default target all: +include ../../py/mkenv.mk +include $(TOP)/py/py.mk + # Zephyr (generated) config files - must be defined before include below Z_EXPORTS = outdir/$(OUTDIR_PREFIX)/Makefile.export ifneq ($(MAKECMDGOALS), clean) include $(Z_EXPORTS) endif -include ../../py/mkenv.mk -include $(TOP)/py/py.mk - INC += -I. INC += -I$(TOP) INC += -I$(BUILD) @@ -56,19 +56,11 @@ SRC_QSTR += $(SRC_C) OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) -CFLAGS = $(KBUILD_CFLAGS) $(NOSTDINC_FLAGS) $(ZEPHYRINCLUDE) \ +CFLAGS = $(Z_CFLAGS) \ -std=gnu99 -fomit-frame-pointer -DNDEBUG -DMICROPY_HEAP_SIZE=$(MICROPY_HEAP_SIZE) $(CFLAGS_EXTRA) $(INC) include $(TOP)/py/mkrules.mk -# We use single target here ($(Z_EXPORTS)) for simplicity, but actually -# number of things get generated here: 'initconfig' generates C header for -# Kconfig configuration, 'outputexports' generates make environment with CC, -# etc., and 'lib' generates other headers which may be included by zephyr.h, -# e.g. DTS-related. -$(Z_EXPORTS): $(CONF_FILE) - $(MAKE) -f Makefile.zephyr BOARD=$(BOARD) CONF_FILE=$(CONF_FILE) initconfig outputexports lib - GENERIC_TARGETS = all zephyr run qemu qemugdb flash debug debugserver KCONFIG_TARGETS = \ initconfig config nconfig menuconfig xconfig gconfig \ @@ -81,7 +73,7 @@ $(GENERIC_TARGETS): $(LIBMICROPYTHON) $(CLEAN_TARGETS): clean $(GENERIC_TARGETS) $(KCONFIG_TARGETS) $(CLEAN_TARGETS): - $(MAKE) -f Makefile.zephyr BOARD=$(BOARD) CONF_FILE=$(CONF_FILE) $@ + $(MAKE) -C outdir/$(BOARD) $@ $(LIBMICROPYTHON): | $(Z_EXPORTS) build/genhdr/qstr.i.last: | $(Z_EXPORTS) @@ -103,3 +95,11 @@ prj_$(BOARD)_merged.conf: prj_base.conf prj_$(BOARD).conf test: cd $(TOP)/tests && ./run-tests --target minimal --device "execpty:make -C ../ports/zephyr run BOARD=$(BOARD) QEMU_PTY=1" + +cmake: outdir/$(BOARD)/Makefile + +outdir/$(BOARD)/Makefile: $(CONF_FILE) + mkdir -p outdir/$(BOARD) && cmake -DBOARD=$(BOARD) -DCONF_FILE=$(CONF_FILE) -Boutdir/$(BOARD) -H. + +$(Z_EXPORTS): outdir/$(BOARD)/Makefile + make --no-print-directory -C outdir/$(BOARD) outputexports CMAKE_COMMAND=: >$@ From b369c1bb9601f83761257d9ba47adef5cbb9ea7b Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 28 Nov 2017 18:19:48 +0200 Subject: [PATCH 062/828] zephyr/Makefile: Make prj_$(BOARD).conf optional, again. This time hopefully should work reliably, using make $(wildcard) function, which in this case either expands to existing prj_$(BOARD).conf file, or to an empty string for non-existing one. --- ports/zephyr/Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ports/zephyr/Makefile b/ports/zephyr/Makefile index ec2bbbcb62..2327cf73c7 100644 --- a/ports/zephyr/Makefile +++ b/ports/zephyr/Makefile @@ -89,8 +89,10 @@ z_clean: $(MAKE) -f Makefile.zephyr BOARD=$(BOARD) clean # This rule is for prj_$(BOARD)_merged.conf, not $(CONF_FILE), which -# can be overriden -prj_$(BOARD)_merged.conf: prj_base.conf prj_$(BOARD).conf +# can be overriden. +# prj_$(BOARD).conf is optional, that's why it's resolved with $(wildcard) +# function. +prj_$(BOARD)_merged.conf: prj_base.conf $(wildcard prj_$(BOARD).conf) $(PYTHON) makeprj.py prj_base.conf prj_$(BOARD).conf $@ test: From 3990a52c0f071a7a48cc276f30785930f31eed39 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 29 Nov 2017 15:43:40 +1100 Subject: [PATCH 063/828] py: Annotate func defs with NORETURN when their corresp decls have it. --- py/objstr.c | 2 +- py/stackctrl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/py/objstr.c b/py/objstr.c index b4f15b38d5..30153813da 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -2084,7 +2084,7 @@ bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) { } } -STATIC void bad_implicit_conversion(mp_obj_t self_in) { +STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("can't convert to str implicitly"); } else { diff --git a/py/stackctrl.c b/py/stackctrl.c index 7cd35fee23..11165b9a6f 100644 --- a/py/stackctrl.c +++ b/py/stackctrl.c @@ -48,7 +48,7 @@ void mp_stack_set_limit(mp_uint_t limit) { MP_STATE_THREAD(stack_limit) = limit; } -void mp_exc_recursion_depth(void) { +NORETURN void mp_exc_recursion_depth(void) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError, MP_OBJ_NEW_QSTR(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded))); } From 8e323b8fa84277531685985327fb682761abd53d Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 29 Nov 2017 16:58:27 +1100 Subject: [PATCH 064/828] py/qstr: Rewrite find_qstr to make manifest that it returns a valid ptr. So long as the input qstr identifier is valid (below the maximum number of qstrs) the function will always return a valid pointer. This patch eliminates the "return 0" dead-code. --- py/qstr.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/py/qstr.c b/py/qstr.c index a3c9612c65..08c3e2505e 100644 --- a/py/qstr.c +++ b/py/qstr.c @@ -127,14 +127,12 @@ void qstr_init(void) { STATIC const byte *find_qstr(qstr q) { // search pool for this qstr - for (qstr_pool_t *pool = MP_STATE_VM(last_pool); pool != NULL; pool = pool->prev) { - if (q >= pool->total_prev_len) { - return pool->qstrs[q - pool->total_prev_len]; - } + // total_prev_len==0 in the final pool, so the loop will always terminate + qstr_pool_t *pool = MP_STATE_VM(last_pool); + while (q < pool->total_prev_len) { + pool = pool->prev; } - - // not found - return 0; + return pool->qstrs[q - pool->total_prev_len]; } // qstr_mutex must be taken while in this function From 74fad3536b961e2ffe08e545b1cf787c0c0b4772 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 29 Nov 2017 17:17:08 +1100 Subject: [PATCH 065/828] py/gc: In gc_realloc, convert pointer sanity checks to assertions. These checks are assumed to be true in all cases where gc_realloc is called with a valid pointer, so no need to waste code space and time checking them in a non-debug build. --- py/gc.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/py/gc.c b/py/gc.c index 9752b3532a..172a5e8fc0 100644 --- a/py/gc.c +++ b/py/gc.c @@ -628,27 +628,18 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { void *ptr = ptr_in; - // sanity check the ptr - if (!VERIFY_PTR(ptr)) { - return NULL; - } - - // get first block - size_t block = BLOCK_FROM_PTR(ptr); - GC_ENTER(); - // sanity check the ptr is pointing to the head of a block - if (ATB_GET_KIND(block) != AT_HEAD) { - GC_EXIT(); - return NULL; - } - if (MP_STATE_MEM(gc_lock_depth) > 0) { GC_EXIT(); return NULL; } + // get the GC block number corresponding to this pointer + assert(VERIFY_PTR(ptr)); + size_t block = BLOCK_FROM_PTR(ptr); + assert(ATB_GET_KIND(block) == AT_HEAD); + // compute number of new blocks that are requested size_t new_blocks = (n_bytes + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK; From 4e056d82cc7cfa1b40c135e1ac544d728231432e Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 30 Nov 2017 10:54:33 +1100 Subject: [PATCH 066/828] esp8266/modules/webrepl_setup: Fix first-time enable of WebREPL. Prior to this fix, enabling WebREPL for the first time via webrepl_setup did not work at all because "boot.py" did not contain any lines with "webrepl" in them that could be uncommented. --- ports/esp8266/modules/webrepl_setup.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/ports/esp8266/modules/webrepl_setup.py b/ports/esp8266/modules/webrepl_setup.py index 5288c49c0c..129313a21c 100644 --- a/ports/esp8266/modules/webrepl_setup.py +++ b/ports/esp8266/modules/webrepl_setup.py @@ -35,12 +35,6 @@ def exists(fname): except OSError: return False -def copy_stream(s_in, s_out): - buf = bytearray(64) - while 1: - sz = s_in.readinto(buf) - s_out.write(buf, sz) - def get_daemon_status(): with open(RC) as f: @@ -51,22 +45,22 @@ def get_daemon_status(): return True return None -def add_daemon(): - with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: - new_f.write("import webrepl\nwebrepl.start()\n") - copy_stream(old_f, new_f) def change_daemon(action): LINES = ("import webrepl", "webrepl.start()") with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False for l in old_f: for patt in LINES: if patt in l: + found = True if action and l.startswith("#"): l = l[1:] elif not action and not l.startswith("#"): l = "#" + l new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") # FatFs rename() is not POSIX compliant, will raise OSError if # dest file exists. os.remove(RC) From 64f11470bec3c4ce9122593d3dd968e4127eb545 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 30 Nov 2017 12:06:41 +1100 Subject: [PATCH 067/828] py/objgenerator: Remove unreachable code for STOP_ITERATION case. This commit essentially reverts aa9dbb1b033a8163e07fcf5763fc20146354cc48 where this if-condition was added. It seems that even when that commit was made the code was never reached by any tests, nor reachable by analysis (see below). The same is true with the code as it currently stands: no test triggers this if-condition, nor any uasyncio examples. Analysing the flow of the program also shows that it's not reachable: ==START== -> to trigger this if condition mp_execute_bytecode() must return MP_VM_RETURN_YIELD with *sp==MP_OBJ_STOP_ITERATION -> mp_execute_bytecode() can only return MP_VM_RETURN_YIELD from the MP_BC_YIELD_VALUE bytecode, which can happen in 2 ways: -> 1) from a "yield " in bytecode, but must always be a proper object, never MP_OBJ_STOP_ITERATION; ==END1== -> 2) via yield from, via mp_resume() which must return MP_VM_RETURN_YIELD with ret_value==MP_OBJ_STOP_ITERATION, which can happen in 3 ways: -> 1) it delegates to mp_obj_gen_resume(); go back to ==START== -> 2) it returns MP_VM_RETURN_YIELD directly but with a guard that ret_val!=MP_OBJ_STOP_ITERATION; ==END2== -> 3) it returns MP_VM_RETURN_YIELD with ret_val set from mp_call_method_n_kw(), but mp_call_method_n_kw() must return a proper object, never MP_OBJ_STOP_ITERATION; ==END3== The above shows there is no way to trigger the if-condition and it can be removed. --- py/objgenerator.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/py/objgenerator.c b/py/objgenerator.c index bf0bbb0e65..9a294debb4 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -125,9 +125,6 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ case MP_VM_RETURN_YIELD: *ret_val = *self->code_state.sp; - if (*ret_val == MP_OBJ_STOP_ITERATION) { - self->code_state.ip = 0; - } break; case MP_VM_RETURN_EXCEPTION: { From 7d25a192206f7effa47c24a52607f00efe86e2ef Mon Sep 17 00:00:00 2001 From: Paul Carver Date: Sun, 26 Nov 2017 11:29:55 -0500 Subject: [PATCH 068/828] docs/library/utime: Fix incorrect example with ticks_diff args order. The parameter order in the example for ticks_diff was incorrect. If it's "too early" that means that scheduled time is greater than current time and if it's "running late" then scheduled time would be less than current time. --- docs/library/utime.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/library/utime.rst b/docs/library/utime.rst index a39f5ee733..7fe83f5abe 100644 --- a/docs/library/utime.rst +++ b/docs/library/utime.rst @@ -187,14 +187,14 @@ Functions # This code snippet is not optimized now = time.ticks_ms() scheduled_time = task.scheduled_time() - if ticks_diff(now, scheduled_time) > 0: + if ticks_diff(scheduled_time, now) > 0: print("Too early, let's nap") - sleep_ms(ticks_diff(now, scheduled_time)) + sleep_ms(ticks_diff(scheduled_time, now)) task.run() - elif ticks_diff(now, scheduled_time) == 0: + elif ticks_diff(scheduled_time, now) == 0: print("Right at time!") task.run() - elif ticks_diff(now, scheduled_time) < 0: + elif ticks_diff(scheduled_time, now) < 0: print("Oops, running late, tell task to run faster!") task.run(run_faster=true) From cb9da2279b021ea7a916cbf16dd0e05c009c22bb Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 30 Nov 2017 20:32:49 +0200 Subject: [PATCH 069/828] docs/uselect: ipoll: Fix grammar/wording of one-shot flag description. --- docs/library/uselect.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/library/uselect.rst b/docs/library/uselect.rst index aa70bec690..211b2a4a80 100644 --- a/docs/library/uselect.rst +++ b/docs/library/uselect.rst @@ -83,10 +83,10 @@ Methods way to poll on streams. If *flags* is 1, one-shot behavior for events is employed: streams for - which events happened, event mask will be automatically reset (equivalent - to ``poll.modify(obj, 0)``), so new events for such a stream won't be - processed until new mask is set with `poll.modify()`. This behavior is - useful for asynchronous I/O schedulers. + which events happened will have their event masks automatically reset + (equivalent to ``poll.modify(obj, 0)``), so new events for such a stream + won't be processed until new mask is set with `poll.modify()`. This + behavior is useful for asynchronous I/O schedulers. .. admonition:: Difference to CPython :class: attention From 8f202319096f3e6a465b0632f5b7783096cc2ee1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Dec 2017 14:48:17 +1100 Subject: [PATCH 070/828] stm32/boards/stm32f767_af.csv: Update AF table based on datasheet. Based on ST datasheet, DocID029041 Rev 3, DM00273119.pdf. --- ports/stm32/boards/stm32f767_af.csv | 160 ++++++++++++++-------------- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/ports/stm32/boards/stm32f767_af.csv b/ports/stm32/boards/stm32f767_af.csv index 1708dfcca4..ab2e248bbf 100644 --- a/ports/stm32/boards/stm32f767_af.csv +++ b/ports/stm32/boards/stm32f767_af.csv @@ -1,64 +1,64 @@ Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15 -,,SYS,TIM1/2,TIM3/4/5,TIM8/9/10/11/LPTIM1/CEC,I2C1/2/3/4/CEC,SPI1/2/3/4/5/6,SPI3/SAI1,SPI2/3/USART1/2/3/UART5/SPDIFRX,SAI2/USART6/UART4/5/7/8/SPDIFRX,CAN1/2/TIM12/13/14/QUADSPI/LCD,SAI2/QUADSPI/SDMMC2/OTG2_HS/OTG1_FS,SDMMC2/ETH,FMC/SDMMC1/OTG2_FS,DCMI,LCD,SYS +,,SYS,I2C4/UART5/TIM1/2,TIM3/4/5,TIM8/9/10/11/LPTIM1/DFSDM1/CEC,I2C1/2/3/4/USART1/CEC,SPI1/I2S1/SPI2/I2S2/SPI3/I2S3/SPI4/5/6,SPI2/I2S2/SPI3/I2S3/SAI1/I2C4/UART4/DFSDM1,SPI2/I2S2/SPI3/I2S3/SPI6/USART1/2/3/UART5/DFSDM1/SPDIF,SPI6/SAI2/USART6/UART4/5/7/8/OTG_FS/SPDIF,CAN1/2/TIM12/13/14/QUADSPI/FMC/LCD,SAI2/QUADSPI/SDMMC2/DFSDM1/OTG2_HS/OTG1_FS/LCD,I2C4/CAN3/SDMMC2/ETH,UART7/FMC/SDMMC1/MDIOS/OTG2_FS,DCMI/LCD/DSI,LCD,SYS PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,SAI2_SD_B,ETH_MII_CRS,,,,EVENTOUT PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,LCD_R2,EVENTOUT -PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,,,LCD_R1,EVENTOUT -PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT -PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT -PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT -PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,DCMI_PIXCLK,LCD_G2,EVENTOUT -PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SD,,,,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT -PortA,PA8,MCO1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,LCD_R6,EVENTOUT -PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,,,,DCMI_D0,,EVENTOUT -PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT -PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT -PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT -PortA,PA13,JTMS,SWDIO,,,,,,,,,,,,,,EVENTOUT -PortA,PA14,JTCK,SWCLK,,,,,,,,,,,,,,EVENTOUT -PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,HDMICEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,,UART4_RTS,,,,,,,EVENTOUT -PortB,PB0,,TIM1_CH2N,TIM3_CH3T,TIM8_CH2N,,,,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT -PortB,PB1,,TIM1_CH3N,TIM3_CH4T,TIM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT -PortB,PB2,,,,,,,SAI1_SD_A,SPI3_MOSI/I2S3_SD,,QUADSPI_CLK,,,,,,EVENTOUT -PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,,,SDMMC2_D2,,,,,EVENTOUT -PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,SPI2_NSS/I2S2_WS,,,SDMMC2_D3,,,,,EVENTOUT -PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,,EVENTOUT -PortB,PB6,,,TIM4_CH1,HDMICEC,I2C1_SCL,,,USART1_TX,,CAN2_TX,QUADSPI_BK1_NCS,,FMC_SDNE1,DCMI_D5,,EVENTOUT -PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,FMC_NL,DCMI_VSYNC,,EVENTOUT -PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,,,,CAN1_RX,SDMMC2_D4,ETH_MII_TXD3,SDMMC1_D4,DCMI_D6,LCD_B6,EVENTOUT -PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,CAN1_TX,SDMMC2_D5,,SDMMC1_D5,DCMI_D7,LCD_B7,EVENTOUT -PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,,USART3_TX,,,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT -PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,,LCD_G5,EVENTOUT -PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,,USART3_CK,,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,,,EVENTOUT -PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,,USART3_CTS,,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,,EVENTOUT -PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,,SPI2_MISO,,USART3_RTS,,TIM12_CH1,SDMMC2_D0,,OTG_HS_DM,,,EVENTOUT -PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,SDMMC2_D1,,OTG_HS_DP,,,EVENTOUT -PortC,PC0,,,,,,,,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT -PortC,PC1,TRACED0,,,,,SPI2_MOSI/I2S2_SD,SAI1_SD_A,,,,,ETH_MDC,,,,EVENTOUT -PortC,PC2,,,,,,SPI2_MISO,,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT -PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT -PortC,PC4,,,,,,I2S1_MCK,,,SPDIFRX_IN2,,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT -PortC,PC5,,,,,,,,,SPDIFRX_IN3,,,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,,,EVENTOUT -PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,,USART6_TX,,SDMMC2_D6,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT -PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,SDMMC2_D7,,SDMMC1_D7,DCMI_D1,LCD_G6,EVENTOUT -PortC,PC8,TRACED1,,TIM3_CH3,TIM8_CH3,,,,UART5_RTS,USART6_CK,,,,SDMMC1_D0,DCMI_D2,,EVENTOUT -PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S2_CKIN,,UART5_CTS,,QUADSPI_BK1_IO0,,,SDMMC1_D1,DCMI_D3,,EVENTOUT -PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,DCMI_D8,LCD_R2,EVENTOUT -PortC,PC11,,,,,,,SPI3_MISO,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,DCMI_D4,,EVENTOUT +PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,MDIOS_MDIO,,LCD_R1,EVENTOUT +PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,LCD_B2,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT +PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,SPI6_NSS,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,SPI6_SCK,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,SPI6_MISO,TIM13_CH1,,,MDIOS_MDC,DCMI_PIXCLK,LCD_G2,EVENTOUT +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SD,,,SPI6_MOSI,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT +PortA,PA8,MCO1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,CAN3_RX,UART7_RX,LCD_B3,LCD_R6,EVENTOUT +PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,,,,DCMI_D0,LCD_R5,EVENTOUT +PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,LCD_B4,OTG_FS_ID,,MDIOS_MDIO,DCMI_D1,LCD_B1,EVENTOUT +PortA,PA11,,TIM1_CH4,,,,SPI2_NSS/I2S2_WS,UART4_RX,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT +PortA,PA12,,TIM1_ETR,,,,SPI2_SCK/I2S2_CK,UART4_TX,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT +PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,HDMI_CEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,SPI6_NSS,UART4_RTS,,,CAN3_TX,UART7_TX,,,EVENTOUT +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,DFSDM1_CKOUT,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,LCD_G1,EVENTOUT +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM1_DATAIN1,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,LCD_G0,EVENTOUT +PortB,PB2,,,,,,,SAI1_SD_A,SPI3_MOSI/I2S3_SD,,QUADSPI_CLK,DFSDM1_CKIN1,,,,,EVENTOUT +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,SPI6_SCK,,SDMMC2_D2,CAN3_RX,UART7_RX,,,EVENTOUT +PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,SPI2_NSS/I2S2_WS,SPI6_MISO,,SDMMC2_D3,CAN3_TX,UART7_TX,,,EVENTOUT +PortB,PB5,,UART5_RX,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,SPI6_MOSI,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,LCD_G7,EVENTOUT +PortB,PB6,,UART5_TX,TIM4_CH1,HDMI_CEC,I2C1_SCL,,DFSDM1_DATAIN5,USART1_TX,,CAN2_TX,QUADSPI_BK1_NCS,I2C4_SCL,FMC_SDNE1,DCMI_D5,,EVENTOUT +PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,DFSDM1_CKIN5,USART1_RX,,,,I2C4_SDA,FMC_NL,DCMI_VSYNC,,EVENTOUT +PortB,PB8,,I2C4_SCL,TIM4_CH3,TIM10_CH1,I2C1_SCL,,DFSDM1_CKIN7,UART5_RX,,CAN1_RX,SDMMC2_D4,ETH_MII_TXD3,SDMMC1_D4,DCMI_D6,LCD_B6,EVENTOUT +PortB,PB9,,I2C4_SDA,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,DFSDM1_DATAIN7,UART5_TX,,CAN1_TX,SDMMC2_D5,I2C4_SMBA,SDMMC1_D5,DCMI_D7,LCD_B7,EVENTOUT +PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,DFSDM1_DATAIN7,USART3_TX,,QUADSPI_BK1_NCS,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT +PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,DFSDM1_CKIN7,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DSI_TE,LCD_G5,EVENTOUT +PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,DFSDM1_DATAIN1,USART3_CK,UART5_RX,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,,,EVENTOUT +PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,DFSDM1_CKIN1,USART3_CTS,UART5_TX,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,,EVENTOUT +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,USART1_TX,SPI2_MISO,DFSDM1_DATAIN2,USART3_RTS,UART4_RTS,TIM12_CH1,SDMMC2_D0,,OTG_HS_DM,,,EVENTOUT +PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,USART1_RX,SPI2_MOSI/I2S2_SD,DFSDM1_CKIN2,,UART4_CTS,TIM12_CH2,SDMMC2_D1,,OTG_HS_DP,,,EVENTOUT +PortC,PC0,,,,DFSDM1_CKIN0,,,DFSDM1_DATAIN4,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT +PortC,PC1,TRACED0,,,DFSDM1_DATAIN0,,SPI2_MOSI/I2S2_SD,SAI1_SD_A,,,,DFSDM1_CKIN4,ETH_MDC,MDIOS_MDC,,,EVENTOUT +PortC,PC2,,,,DFSDM1_CKIN1,,SPI2_MISO,DFSDM1_CKOUT,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT +PortC,PC3,,,,DFSDM1_DATAIN1,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT +PortC,PC4,,,,DFSDM1_CKIN2,,I2S1_MCK,,,SPDIFRX_IN2,,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT +PortC,PC5,,,,DFSDM1_DATAIN2,,,,,SPDIFRX_IN3,,,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,,,EVENTOUT +PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,DFSDM1_CKIN3,USART6_TX,FMC_NWAIT,SDMMC2_D6,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT +PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,DFSDM1_DATAIN3,USART6_RX,FMC_NE1,SDMMC2_D7,,SDMMC1_D7,DCMI_D1,LCD_G6,EVENTOUT +PortC,PC8,TRACED1,,TIM3_CH3,TIM8_CH3,,,,UART5_RTS,USART6_CK,FMC_NE2/FMC_NCE,,,SDMMC1_D0,DCMI_D2,,EVENTOUT +PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,UART5_CTS,,QUADSPI_BK1_IO0,LCD_G3,,SDMMC1_D1,DCMI_D3,LCD_B2,EVENTOUT +PortC,PC10,,,,DFSDM1_CKIN5,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,DCMI_D8,LCD_R2,EVENTOUT +PortC,PC11,,,,DFSDM1_DATAIN5,,,SPI3_MISO,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,DCMI_D4,,EVENTOUT PortC,PC12,TRACED3,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDMMC1_CK,DCMI_D9,,EVENTOUT PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT -PortD,PD0,,,,,,,,,,CAN1_RX,,,FMC_D2,,,EVENTOUT -PortD,PD1,,,,,,,,,,CAN1_TX,,,FMC_D3,,,EVENTOUT +PortD,PD0,,,,DFSDM1_CKIN6,,,DFSDM1_DATAIN7,,UART4_RX,CAN1_RX,,,FMC_D2,,,EVENTOUT +PortD,PD1,,,,DFSDM1_DATAIN6,,,DFSDM1_CKIN7,,UART4_TX,CAN1_TX,,,FMC_D3,,,EVENTOUT PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,DCMI_D11,,EVENTOUT -PortD,PD3,,,,,,SPI2_SCK/I2S2_CK,,USART2_CTS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT -PortD,PD4,,,,,,,,USART2_RTS,,,,,FMC_NOE,,,EVENTOUT +PortD,PD3,,,,DFSDM1_CKOUT,,SPI2_SCK/I2S2_CK,DFSDM1_DATAIN0,USART2_CTS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT +PortD,PD4,,,,,,,DFSDM1_CKIN0,USART2_RTS,,,,,FMC_NOE,,,EVENTOUT PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT -PortD,PD6,,,,,,SPI3_MOSI/I2S3_SD,SAI1_SD_A,USART2_RX,,,,SDMMC2_CK,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT -PortD,PD7,,,,,,,,USART2_CK,SPDIFRX_IN0,,,SDMMC2_CMD,FMC_NE1,,,EVENTOUT -PortD,PD8,,,,,,,,USART3_TX,SPDIFRX_IN1,,,,FMC_D13,,,EVENTOUT -PortD,PD9,,,,,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT -PortD,PD10,,,,,,,,USART3_CK,,,,,FMC_D15,,LCD_B3,EVENTOUT +PortD,PD6,,,,DFSDM1_CKIN4,,SPI3_MOSI/I2S3_SD,SAI1_SD_A,USART2_RX,,,DFSDM1_DATAIN1,SDMMC2_CK,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT +PortD,PD7,,,,DFSDM1_DATAIN4,,SPI1_MOSI/I2S1_SD,DFSDM1_CKIN1,USART2_CK,SPDIFRX_IN0,,,SDMMC2_CMD,FMC_NE1,,,EVENTOUT +PortD,PD8,,,,DFSDM1_CKIN3,,,,USART3_TX,SPDIFRX_IN1,,,,FMC_D13,,,EVENTOUT +PortD,PD9,,,,DFSDM1_DATAIN3,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT +PortD,PD10,,,,DFSDM1_CKOUT,,,,USART3_CK,,,,,FMC_D15,,LCD_B3,EVENTOUT PortD,PD11,,,,,I2C4_SMBA,,,USART3_CTS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16/FMC_CLE,,,EVENTOUT PortD,PD12,,,TIM4_CH1,LPTIM1_IN1,I2C4_SCL,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17/FMC_ALE,,,EVENTOUT PortD,PD13,,,TIM4_CH2,LPTIM1_OUT,I2C4_SDA,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT @@ -68,16 +68,16 @@ PortE,PE0,,,TIM4_ETR,LPTIM1_ETR,,,,,UART8_RX,,SAI2_MCK_A,,FMC_NBL0,DCMI_D2,,EVEN PortE,PE1,,,,LPTIM1_IN2,,,,,UART8_TX,,,,FMC_NBL1,DCMI_D3,,EVENTOUT PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,QUADSPI_BK1_IO2,,ETH_MII_TXD3,FMC_A23,,,EVENTOUT PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT -PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT -PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT +PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,DFSDM1_DATAIN3,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT +PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,DFSDM1_CKIN3,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT PortE,PE6,TRACED3,TIM1_BKIN2,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,SAI2_MCK_B,,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT -PortE,PE7,,TIM1_ETR,,,,,,,UART7_RX,,QUADSPI_BK2_IO0,,FMC_D4,,,EVENTOUT -PortE,PE8,,TIM1_CH1N,,,,,,,UART7_TX,,QUADSPI_BK2_IO1,,FMC_D5,,,EVENTOUT -PortE,PE9,,TIM1_CH1,,,,,,,UART7_RTS,,QUADSPI_BK2_IO2,,FMC_D6,,,EVENTOUT -PortE,PE10,,TIM1_CH2N,,,,,,,UART7_CTS,,QUADSPI_BK2_IO3,,FMC_D7,,,EVENTOUT -PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,,,,,SAI2_SD_B,,FMC_D8,,LCD_G3,EVENTOUT -PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,,,,,SAI2_SCK_B,,FMC_D9,,LCD_B4,EVENTOUT -PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,,,,,SAI2_FS_B,,FMC_D10,,LCD_DE,EVENTOUT +PortE,PE7,,TIM1_ETR,,,,,DFSDM1_DATAIN2,,UART7_RX,,QUADSPI_BK2_IO0,,FMC_D4,,,EVENTOUT +PortE,PE8,,TIM1_CH1N,,,,,DFSDM1_CKIN2,,UART7_TX,,QUADSPI_BK2_IO1,,FMC_D5,,,EVENTOUT +PortE,PE9,,TIM1_CH1,,,,,DFSDM1_CKOUT,,UART7_RTS,,QUADSPI_BK2_IO2,,FMC_D6,,,EVENTOUT +PortE,PE10,,TIM1_CH2N,,,,,DFSDM1_DATAIN4,,UART7_CTS,,QUADSPI_BK2_IO3,,FMC_D7,,,EVENTOUT +PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,DFSDM1_CKIN4,,,,SAI2_SD_B,,FMC_D8,,LCD_G3,EVENTOUT +PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,DFSDM1_DATAIN5,,,,SAI2_SCK_B,,FMC_D9,,LCD_B4,EVENTOUT +PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,DFSDM1_CKIN5,,,,SAI2_FS_B,,FMC_D10,,LCD_DE,EVENTOUT PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCK_B,,FMC_D11,,LCD_CLK,EVENTOUT PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FMC_D12,,LCD_R7,EVENTOUT PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT @@ -90,11 +90,11 @@ PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_RX,QUADSPI_BK1_IO3,,,,,,EVENTO PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_TX,QUADSPI_BK1_IO2,,,,,,EVENTOUT PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,UART7_RTS,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,UART7_CTS,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT -PortF,PF10,,,,,,,,,,,,,,DCMI_D11,LCD_DE,EVENTOUT +PortF,PF10,,,,,,,,,,QUADSPI_CLK,,,,DCMI_D11,LCD_DE,EVENTOUT PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,DCMI_D12,,EVENTOUT PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT -PortF,PF13,,,,,I2C4_SMBA,,,,,,,,FMC_A7,,,EVENTOUT -PortF,PF14,,,,,I2C4_SCL,,,,,,,,FMC_A8,,,EVENTOUT +PortF,PF13,,,,,I2C4_SMBA,,DFSDM1_DATAIN6,,,,,,FMC_A7,,,EVENTOUT +PortF,PF14,,,,,I2C4_SCL,,DFSDM1_CKIN6,,,,,,FMC_A8,,,EVENTOUT PortF,PF15,,,,,I2C4_SDA,,,,,,,,FMC_A9,,,EVENTOUT PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT @@ -102,12 +102,12 @@ PortG,PG2,,,,,,,,,,,,,FMC_A12,,,EVENTOUT PortG,PG3,,,,,,,,,,,,,FMC_A13,,,EVENTOUT PortG,PG4,,,,,,,,,,,,,FMC_A14/FMC_BA0,,,EVENTOUT PortG,PG5,,,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT -PortG,PG6,,,,,,,,,,,,,,DCMI_D12,LCD_R7,EVENTOUT -PortG,PG7,,,,,,,,,USART6_CK,,,,FMC_INT,DCMI_D13,LCD_CLK,EVENTOUT -PortG,PG8,,,,,,SPI6_NSS,,SPDIFRX_IN2,USART6_RTS,,,ETH_PPS_OUT,FMC_SDCLK,,,EVENTOUT -PortG,PG9,,,,,,,,SPDIFRX_IN3,USART6_RX,QUADSPI_BK2_IO2,SAI2_FS_B,SDMMC2_D0,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT -PortG,PG10,,,,,,,,,,LCD_G3,SAI2_SD_B,SDMMC2_D1,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT -PortG,PG11,,,,,,,,SPDIFRX_IN0,,,SDMMC2_D2,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DCMI_D3,LCD_B3,EVENTOUT +PortG,PG6,,,,,,,,,,,,,FMC_NE3,DCMI_D12,LCD_R7,EVENTOUT +PortG,PG7,,,,,,,SAI1_MCLK_A,,USART6_CK,,,,FMC_INT,DCMI_D13,LCD_CLK,EVENTOUT +PortG,PG8,,,,,,SPI6_NSS,,SPDIFRX_IN2,USART6_RTS,,,ETH_PPS_OUT,FMC_SDCLK,,LCD_G7,EVENTOUT +PortG,PG9,,,,,,SPI1_MISO,,SPDIFRX_IN3,USART6_RX,QUADSPI_BK2_IO2,SAI2_FS_B,SDMMC2_D0,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT +PortG,PG10,,,,,,SPI1_NSS/I2S1_WS,,,,LCD_G3,SAI2_SD_B,SDMMC2_D1,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT +PortG,PG11,,,,,,SPI1_SCK/I2S1_CK,,SPDIFRX_IN0,,,SDMMC2_D2,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DCMI_D3,LCD_B3,EVENTOUT PortG,PG12,,,,LPTIM1_IN1,,SPI6_MISO,,SPDIFRX_IN1,USART6_RTS,LCD_B4,,SDMMC2_D3,FMC_NE4,,LCD_B1,EVENTOUT PortG,PG13,TRACED0,,,LPTIM1_OUT,,SPI6_SCK,,,USART6_CTS,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,LCD_R0,EVENTOUT PortG,PG14,TRACED1,,,LPTIM1_ETR,,SPI6_MOSI,,,USART6_TX,QUADSPI_BK2_IO3,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,LCD_B0,EVENTOUT @@ -116,7 +116,7 @@ PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT PortH,PH2,,,,LPTIM1_IN2,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT -PortH,PH4,,,,,I2C2_SCL,,,,,,OTG_HS_ULPI_NXT,,,,,EVENTOUT +PortH,PH4,,,,,I2C2_SCL,,,,,LCD_G5,OTG_HS_ULPI_NXT,,,,LCD_G4,EVENTOUT PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT PortH,PH6,,,,,I2C2_SMBA,SPI5_SCK,,,,TIM12_CH1,,ETH_MII_RXD2,FMC_SDNE1,DCMI_D8,,EVENTOUT PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,EVENTOUT @@ -125,8 +125,8 @@ PortH,PH9,,,,,I2C3_SMBA,,,,,TIM12_CH2,,,FMC_D17,DCMI_D0,LCD_R3,EVENTOUT PortH,PH10,,,TIM5_CH1,,I2C4_SMBA,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT PortH,PH11,,,TIM5_CH2,,I2C4_SCL,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT PortH,PH12,,,TIM5_CH3,,I2C4_SDA,,,,,,,,FMC_D20,DCMI_D3,LCD_R6,EVENTOUT -PortH,PH13,,,,TIM8_CH1N,,,,,,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT -PortH,PH14,,,,TIM8_CH2N,,,,,,,,,FMC_D22,DCMI_D4,LCD_G3,EVENTOUT +PortH,PH13,,,,TIM8_CH1N,,,,,UART4_TX,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT +PortH,PH14,,,,TIM8_CH2N,,,,,UART4_RX,CAN1_RX,,,FMC_D22,DCMI_D4,LCD_G3,EVENTOUT PortH,PH15,,,,TIM8_CH3N,,,,,,,,,FMC_D23,DCMI_D11,LCD_G4,EVENTOUT PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,,,,FMC_D24,DCMI_D13,LCD_G5,EVENTOUT PortI,PI1,,,,TIM8_BKIN2,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT @@ -137,16 +137,16 @@ PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,DCMI_D7,LCD_B7,EVENTOUT PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT -PortI,PI9,,,,,,,,,,CAN1_RX,,,FMC_D30,,LCD_VSYNC,EVENTOUT +PortI,PI9,,,,,,,,,UART4_RX,CAN1_RX,,,FMC_D30,,LCD_VSYNC,EVENTOUT PortI,PI10,,,,,,,,,,,,ETH_MII_RX_ER,FMC_D31,,LCD_HSYNC,EVENTOUT -PortI,PI11,,,,,,,,,,,OTG_HS_ULPI_DIR,,,,,EVENTOUT +PortI,PI11,,,,,,,,,,LCD_G6,OTG_HS_ULPI_DIR,,,,,EVENTOUT PortI,PI12,,,,,,,,,,,,,,,LCD_HSYNC,EVENTOUT PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT -PortI,PI15,,,,,,,,,,,,,,,LCD_R0,EVENTOUT -PortJ,PJ0,,,,,,,,,,,,,,,LCD_R1,EVENTOUT +PortI,PI15,,,,,,,,,,LCD_G2,,,,,LCD_R0,EVENTOUT +PortJ,PJ0,,,,,,,,,,LCD_R7,,,,,LCD_R1,EVENTOUT PortJ,PJ1,,,,,,,,,,,,,,,LCD_R2,EVENTOUT -PortJ,PJ2,,,,,,,,,,,,,,,LCD_R3,EVENTOUT +PortJ,PJ2,,,,,,,,,,,,,,DSI_TE,LCD_R3,EVENTOUT PortJ,PJ3,,,,,,,,,,,,,,,LCD_R4,EVENTOUT PortJ,PJ4,,,,,,,,,,,,,,,LCD_R5,EVENTOUT PortJ,PJ5,,,,,,,,,,,,,,,LCD_R6,EVENTOUT @@ -156,8 +156,8 @@ PortJ,PJ8,,,,,,,,,,,,,,,LCD_G1,EVENTOUT PortJ,PJ9,,,,,,,,,,,,,,,LCD_G2,EVENTOUT PortJ,PJ10,,,,,,,,,,,,,,,LCD_G3,EVENTOUT PortJ,PJ11,,,,,,,,,,,,,,,LCD_G4,EVENTOUT -PortJ,PJ12,,,,,,,,,,,,,,,LCD_B0,EVENTOUT -PortJ,PJ13,,,,,,,,,,,,,,,LCD_B1,EVENTOUT +PortJ,PJ12,,,,,,,,,,LCD_G3,,,,,LCD_B0,EVENTOUT +PortJ,PJ13,,,,,,,,,,LCD_G4,,,,,LCD_B1,EVENTOUT PortJ,PJ14,,,,,,,,,,,,,,,LCD_B2,EVENTOUT PortJ,PJ15,,,,,,,,,,,,,,,LCD_B3,EVENTOUT PortK,PK0,,,,,,,,,,,,,,,LCD_G5,EVENTOUT From 6515acca704a1ac208afb79e407486b58a0781de Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Dec 2017 14:51:36 +1100 Subject: [PATCH 071/828] stm32/boards/*_af.csv: Make consistent use of JTMS, JTCK, SWDIO, SWCLK. 5-pin JTAG and 2-pin SWD are logically separate interfaces so encode them in the AF tables as separate entries (separated by /, not -). --- ports/stm32/boards/stm32f401_af.csv | 4 ++-- ports/stm32/boards/stm32f405_af.csv | 4 ++-- ports/stm32/boards/stm32f411_af.csv | 4 ++-- ports/stm32/boards/stm32f429_af.csv | 4 ++-- ports/stm32/boards/stm32f439_af.csv | 4 ++-- ports/stm32/boards/stm32l476_af.csv | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ports/stm32/boards/stm32f401_af.csv b/ports/stm32/boards/stm32f401_af.csv index 3b29e13495..bdcf9a1fe5 100644 --- a/ports/stm32/boards/stm32f401_af.csv +++ b/ports/stm32/boards/stm32f401_af.csv @@ -13,8 +13,8 @@ PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,OTG_FS_VBUS,,,,,EVENTOUT, PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,,,EVENTOUT, PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,USART6_TX,,OTG_FS_DM,,,,,EVENTOUT, PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,USART6_RX,,OTG_FS_DP,,,,,EVENTOUT, -PortA,PA13,JTMS_SWDIO,,,,,,,,,,,,,,,EVENTOUT, -PortA,PA14,JTCK_SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT, PortB,PB0,,TIM1_CH2N,TIM3_CH3,,,,,,,,,,,,,EVENTOUT,ADC1_IN8 PortB,PB1,,TIM1_CH3N,TIM3_CH4,,,,,,,,,,,,,EVENTOUT,ADC1_IN9 diff --git a/ports/stm32/boards/stm32f405_af.csv b/ports/stm32/boards/stm32f405_af.csv index 81f5e80ed1..e6d8fcc2b5 100644 --- a/ports/stm32/boards/stm32f405_af.csv +++ b/ports/stm32/boards/stm32f405_af.csv @@ -13,8 +13,8 @@ PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,,,,DCMI_D0,,EVENTOUT, PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT, PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,,EVENTOUT, PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT, -PortA,PA13,JTMS-SWDIO,,,,,,,,,,,,,,,EVENTOUT, -PortA,PA14,JTCK-SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT, PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,,,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT,ADC12_IN8 PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT,ADC12_IN9 diff --git a/ports/stm32/boards/stm32f411_af.csv b/ports/stm32/boards/stm32f411_af.csv index 29267b1d95..4fe794121b 100644 --- a/ports/stm32/boards/stm32f411_af.csv +++ b/ports/stm32/boards/stm32f411_af.csv @@ -13,8 +13,8 @@ PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,USB_FS_VBUS,,SDIO_D2,,,EVENTOUT, PortA,PA10,,TIM1_CH3,,,,,SPI5_MOSI/I2S5_SD,USART1_RX,,,USB_FS_ID,,,,,EVENTOUT, PortA,PA11,,TIM1_CH4,,,,,SPI4_MISO,USART1_CTS,USART6_TX,,USB_FS_DM,,,,,EVENTOUT, PortA,PA12,,TIM1_ETR,,,,,SPI5_MISO,USART1_RTS,USART6_RX,,USB_FS_DP,,,,,EVENTOUT, -PortA,PA13,JTMS-SWDIO,,,,,,,,,,,,,,,EVENTOUT, -PortA,PA14,JTCK-SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART1_TX,,,,,,,,EVENTOUT, PortB,PB0,,TIM1_CH2N,TIM3_CH3,,,,SPI5_SCK/I2S5_CK,,,,,,,,,EVENTOUT,ADC1_IN8 PortB,PB1,,TIM1_CH3N,TIM3_CH4,,,,SPI5_NSS/I2S5_WS,,,,,,,,,EVENTOUT,ADC1_IN9 diff --git a/ports/stm32/boards/stm32f429_af.csv b/ports/stm32/boards/stm32f429_af.csv index 2e501ade0b..4ee8edd703 100644 --- a/ports/stm32/boards/stm32f429_af.csv +++ b/ports/stm32/boards/stm32f429_af.csv @@ -13,8 +13,8 @@ PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,,,,DCMI_D0,,EVENTOUT, PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT, PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT, PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT, -PortA,PA13,JTMS-SWDIO,,,,,,,,,,,,,,,EVENTOUT, -PortA,PA14,JTCK-SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT, PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT,ADC12_IN8 PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT,ADC12_IN9 diff --git a/ports/stm32/boards/stm32f439_af.csv b/ports/stm32/boards/stm32f439_af.csv index 5d5c3e72d6..dc36415024 100644 --- a/ports/stm32/boards/stm32f439_af.csv +++ b/ports/stm32/boards/stm32f439_af.csv @@ -13,8 +13,8 @@ PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,,,,DCMI_D0,,EVENTOUT, PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT, PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT, PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT, -PortA,PA13,JTMS-SWDIO,,,,,,,,,,,,,,,EVENTOUT, -PortA,PA14,JTCK-SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT, PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT,ADC12_IN8 PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT,ADC12_IN9 diff --git a/ports/stm32/boards/stm32l476_af.csv b/ports/stm32/boards/stm32l476_af.csv index d67c33880f..a78fc45aba 100644 --- a/ports/stm32/boards/stm32l476_af.csv +++ b/ports/stm32/boards/stm32l476_af.csv @@ -13,8 +13,8 @@ PortA,PA9,,TIM1_CH2,,,,,,USART1_TX,,,,LCD_COM1,,,TIM15_BKIN,EVENTOUT,, PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,LCD_COM2,,,TIM17_BKIN,EVENTOUT,, PortA,PA11,,TIM1_CH4,TIM1_BKIN2,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,TIM1_BKIN2_COMP1,,,EVENTOUT,, PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS_DE,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT,, -PortA,PA13,JTMS-SWDIO,IR_OUT,,,,,,,,,OTG_FS_NOE,,,,,EVENTOUT,, -PortA,PA14,JTCK-SWCLK,,,,,,,,,,,,,,,EVENTOUT,, +PortA,PA13,JTMS/SWDIO,IR_OUT,,,,,,,,,OTG_FS_NOE,,,,,EVENTOUT,, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT,, PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,,,SPI1_NSS,SPI3_NSS,,UART4_RTS_DE,TSC_G3_IO1,,LCD_SEG17,,SAI2_FS_B,,EVENTOUT,, PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,USART3_CK,,,QUADSPI_BK1_IO1,LCD_SEG5,COMP1_OUT,,,EVENTOUT,ADC12_IN15, PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM_DATIN0,USART3_RTS_DE,,,QUADSPI_BK1_IO0,LCD_SEG6,,,LPTIM2_IN1,EVENTOUT,ADC12_IN16,COMP1_INN From bb047558da6d7e1857e1d4c79547776976353cd3 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 1 Dec 2017 13:45:03 +0200 Subject: [PATCH 072/828] zephyr/Makefile: syscall_macros.h generation was moved from CMake to make. Required for #include to work. --- ports/zephyr/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/zephyr/Makefile b/ports/zephyr/Makefile index 2327cf73c7..d6d711d1c2 100644 --- a/ports/zephyr/Makefile +++ b/ports/zephyr/Makefile @@ -105,3 +105,4 @@ outdir/$(BOARD)/Makefile: $(CONF_FILE) $(Z_EXPORTS): outdir/$(BOARD)/Makefile make --no-print-directory -C outdir/$(BOARD) outputexports CMAKE_COMMAND=: >$@ + make -C outdir/$(BOARD) syscall_macros_h_target From 4fee35a32c600d603034b6eb077a55899513ba4d Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 3 Dec 2017 15:07:46 +0200 Subject: [PATCH 073/828] docs/glossary: Describe the callee-owned tuple concept. --- docs/library/uselect.rst | 4 ++-- docs/reference/glossary.rst | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/docs/library/uselect.rst b/docs/library/uselect.rst index 211b2a4a80..f88ab7d1d9 100644 --- a/docs/library/uselect.rst +++ b/docs/library/uselect.rst @@ -78,8 +78,8 @@ Methods .. method:: poll.ipoll(timeout=-1, flags=0) - Like :meth:`poll.poll`, but instead returns an iterator which yields - `callee-owned tuples`. This function provides efficient, allocation-free + Like :meth:`poll.poll`, but instead returns an iterator which yields a + `callee-owned tuple`. This function provides an efficient, allocation-free way to poll on streams. If *flags* is 1, one-shot behavior for events is employed: streams for diff --git a/docs/reference/glossary.rst b/docs/reference/glossary.rst index 4cd3d84cc5..b6153550c0 100644 --- a/docs/reference/glossary.rst +++ b/docs/reference/glossary.rst @@ -15,6 +15,29 @@ Glossary may also refer to "boardless" ports like :term:`Unix port `). + callee-owned tuple + A tuple returned by some builtin function/method, containing data + which is valid for a limited time, usually until next call to the + same function (or a group of related functions). After next call, + data in the tuple may be changed. This leads to the following + restriction on the usage of callee-owned tuples - references to + them cannot be stored. The only valid operation is extracting + values from them (including making a copy). Callee-owned tuples + is a MicroPython-specific construct (not available in the general + Python language), introduced for memory allocation optimization. + The idea is that callee-owned tuple is allocated once and stored + on the callee side. Subsequent calls don't require allocation, + allowing to return multiple values when allocation is not possible + (e.g. in interrupt context) or not desirable (because allocation + inherently leads to memory fragmentation). Note that callee-owned + tuples are effectively mutable tuples, making an exception to + Python's rule that tuples are immutable. (It may be interesting + why tuples were used for such a purpose then, instead of mutable + lists - the reason for that is that lists are mutable from user + application side too, so a user could do things to a callee-owned + list which the callee doesn't expect and could lead to problems; + a tuple is protected from this.) + CPython CPython is the reference implementation of Python programming language, and the most well-known one, which most of the people From 3c483842db18038677a97624d9aafc4cc5b291c4 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 3 Dec 2017 15:32:09 +0200 Subject: [PATCH 074/828] tests/cpydiff: Fix markup where "`" (xref) was used instead of "``" (code). --- tests/cpydiff/builtin_next_arg2.py | 2 +- tests/cpydiff/types_str_ljust_rjust.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cpydiff/builtin_next_arg2.py b/tests/cpydiff/builtin_next_arg2.py index cbde773f90..5df2d6e70f 100644 --- a/tests/cpydiff/builtin_next_arg2.py +++ b/tests/cpydiff/builtin_next_arg2.py @@ -2,7 +2,7 @@ categories: Modules,builtins description: Second argument to next() is not implemented cause: MicroPython is optimised for code space. -workaround: Instead of `val = next(it, deflt)` use:: +workaround: Instead of ``val = next(it, deflt)`` use:: try: val = next(it) diff --git a/tests/cpydiff/types_str_ljust_rjust.py b/tests/cpydiff/types_str_ljust_rjust.py index 4985962059..fa3f594c1f 100644 --- a/tests/cpydiff/types_str_ljust_rjust.py +++ b/tests/cpydiff/types_str_ljust_rjust.py @@ -2,6 +2,6 @@ categories: Types,str description: str.ljust() and str.rjust() not implemented cause: MicroPython is highly optimized for memory usage. Easy workarounds available. -workaround: Instead of `s.ljust(10)` use `"%-10s" % s`, instead of `s.rjust(10)` use `"% 10s" % s`. Alternatively, `"{:<10}".format(s)` or `"{:>10}".format(s)`. +workaround: Instead of ``s.ljust(10)`` use ``"%-10s" % s``, instead of ``s.rjust(10)`` use ``"% 10s" % s``. Alternatively, ``"{:<10}".format(s)`` or ``"{:>10}".format(s)``. """ print('abc'.ljust(10)) From 140acc9a322c1b575d30115604fb1d3250277c0d Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 3 Dec 2017 15:50:37 +0200 Subject: [PATCH 075/828] docs/uerrno: Fix xref-vs-code markup. --- docs/library/uerrno.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/library/uerrno.rst b/docs/library/uerrno.rst index 0cdcc84487..e336eb5c5c 100644 --- a/docs/library/uerrno.rst +++ b/docs/library/uerrno.rst @@ -17,7 +17,7 @@ Constants Error codes, based on ANSI C/POSIX standard. All error codes start with "E". As mentioned above, inventory of the codes depends on `MicroPython port`. Errors are usually accessible as ``exc.args[0]`` - where `exc` is an instance of `OSError`. Usage example:: + where ``exc`` is an instance of `OSError`. Usage example:: try: uos.mkdir("my_dir") From 8175f1608eddc61c495c9163aebcc3c90549b9c4 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 3 Dec 2017 18:56:18 +0200 Subject: [PATCH 076/828] docs/glossary: Describe "stream" term. --- docs/reference/glossary.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/reference/glossary.rst b/docs/reference/glossary.rst index b6153550c0..d9650bdd8d 100644 --- a/docs/reference/glossary.rst +++ b/docs/reference/glossary.rst @@ -120,6 +120,16 @@ Glossary from context, it's recommended to use full specification like one of the above. + stream + Also known as a "file-like object". An object which provides sequential + read-write access to the underlying data. A stream object implements + a corresponding interface, which consists of methods like ``read()``, + ``write()``, ``readinto()``, ``seek()``, ``flush()``, ``close()``, etc. + A stream is an important concept in MicroPython, many I/O objects + implement the stream interface, and thus can be used consistently and + interchangeably in different contexts. For more information on + streams in MicroPython, see `uio` module. + upip (Literally, "micro pip"). A package manage for MicroPython, inspired by :term:`CPython`'s pip, but much smaller and with reduced functionality. From 3a431fba50c96cc47d8273a6934e200993197b14 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 4 Dec 2017 00:13:10 +0200 Subject: [PATCH 077/828] esp8266/modnetwork: Make sure to intern string passed to .config("param"). This is the proper fix for https://github.com/micropython/micropython/issues/3442. --- ports/esp8266/modnetwork.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/ports/esp8266/modnetwork.c b/ports/esp8266/modnetwork.c index 4066c969ce..f7da5b7510 100644 --- a/ports/esp8266/modnetwork.c +++ b/ports/esp8266/modnetwork.c @@ -402,30 +402,30 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs mp_obj_t val; - #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x) - switch ((uintptr_t)args[1]) { - case QS(MP_QSTR_mac): { + qstr key = mp_obj_str_get_qstr(args[1]); + switch (key) { + case MP_QSTR_mac: { uint8_t mac[6]; wifi_get_macaddr(self->if_id, mac); return mp_obj_new_bytes(mac, sizeof(mac)); } - case QS(MP_QSTR_essid): + case MP_QSTR_essid: req_if = SOFTAP_IF; val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len); break; - case QS(MP_QSTR_hidden): + case MP_QSTR_hidden: req_if = SOFTAP_IF; val = mp_obj_new_bool(cfg.ap.ssid_hidden); break; - case QS(MP_QSTR_authmode): + case MP_QSTR_authmode: req_if = SOFTAP_IF; val = MP_OBJ_NEW_SMALL_INT(cfg.ap.authmode); break; - case QS(MP_QSTR_channel): + case MP_QSTR_channel: req_if = SOFTAP_IF; val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel); break; - case QS(MP_QSTR_dhcp_hostname): { + case MP_QSTR_dhcp_hostname: { req_if = STATION_IF; char* s = wifi_station_get_hostname(); val = mp_obj_new_str(s, strlen(s)); @@ -434,7 +434,6 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs default: goto unknown; } - #undef QS // We post-check interface requirements to save on code size if (req_if >= 0) { From 155ec21e4933f75ee98bbd3e125e4304fb188170 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 4 Dec 2017 01:01:03 +0200 Subject: [PATCH 078/828] docs/glossary: Describe string interning. --- docs/reference/glossary.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/reference/glossary.rst b/docs/reference/glossary.rst index d9650bdd8d..98a2a50d8d 100644 --- a/docs/reference/glossary.rst +++ b/docs/reference/glossary.rst @@ -64,6 +64,22 @@ Glossary properties of these pins (e.g. controllable by the same register). + interned string + A string referenced by its (unique) identity rather than its + address. Interned strings are thus can be quickly compared just + by their identifiers, instead of comparing by content. The + drawbacks of interned strings are that interning operation takes + time (proportional to the number of existing interned strings, + i.e. becoming slower and slower over time) and that the space + used for interned strings is not reclaimable. String interning + is done automatically by MicroPython compiler and runtimer when + it's either required by the implementation (e.g. function keyword + arguments are represented by interned string id's) or deemed + beneficial (e.g. for short enough strings, which have a chance + to be repeated, and thus interning them would save memory on + copies). Most of string and I/O operations don't produce interned + strings due to drawbacks described above. + MCU Microcontroller. Microcontrollers usually have much less resources than a full-fledged computing system, but smaller, cheaper and From 75d3c046dafa84dad51ed757f832c2dad2934bf9 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 4 Dec 2017 11:05:49 +0200 Subject: [PATCH 079/828] py/misc.h: Add m_new_obj_var_with_finaliser(). Similar to existing m_new_obj_with_finaliser(). --- py/misc.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/py/misc.h b/py/misc.h index b9f2dae901..5d557db6fe 100644 --- a/py/misc.h +++ b/py/misc.h @@ -63,8 +63,10 @@ typedef unsigned int uint; #define m_new_obj_var_maybe(obj_type, var_type, var_num) ((obj_type*)m_malloc_maybe(sizeof(obj_type) + sizeof(var_type) * (var_num))) #if MICROPY_ENABLE_FINALISER #define m_new_obj_with_finaliser(type) ((type*)(m_malloc_with_finaliser(sizeof(type)))) +#define m_new_obj_var_with_finaliser(type, var_type, var_num) ((type*)m_malloc_with_finaliser(sizeof(type) + sizeof(var_type) * (var_num))) #else #define m_new_obj_with_finaliser(type) m_new_obj(type) +#define m_new_obj_var_with_finaliser(type, var_type, var_num) m_new_obj_var(type, var_type, var_num) #endif #if MICROPY_MALLOC_USES_ALLOCATED_SIZE #define m_renew(type, ptr, old_num, new_num) ((type*)(m_realloc((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num)))) From 3ff7040c8ab268777e940a9bed4aa7c24f50ba31 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 4 Dec 2017 18:36:20 +0200 Subject: [PATCH 080/828] docs/library: Add xrefs to "stream" dictionary entry for many modules. --- docs/library/btree.rst | 2 +- docs/library/machine.UART.rst | 2 +- docs/library/pyb.UART.rst | 2 +- docs/library/pyb.USB_VCP.rst | 4 ++-- docs/library/sys.rst | 6 +++--- docs/library/uio.rst | 2 +- docs/library/uos.rst | 2 +- docs/library/uselect.rst | 4 ++-- docs/library/usocket.rst | 4 ++-- docs/library/ussl.rst | 4 ++-- docs/library/uzlib.rst | 2 +- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/library/btree.rst b/docs/library/btree.rst index 8fac67e8d4..3578acd8fd 100644 --- a/docs/library/btree.rst +++ b/docs/library/btree.rst @@ -5,7 +5,7 @@ :synopsis: simple BTree database The ``btree`` module implements a simple key-value database using external -storage (disk files, or in general case, a random-access stream). Keys are +storage (disk files, or in general case, a random-access `stream`). Keys are stored sorted in the database, and besides efficient retrieval by a key value, a database also supports efficient ordered range scans (retrieval of values with the keys in a given range). On the application interface diff --git a/docs/library/machine.UART.rst b/docs/library/machine.UART.rst index 983ef0a947..1574f17db9 100644 --- a/docs/library/machine.UART.rst +++ b/docs/library/machine.UART.rst @@ -24,7 +24,7 @@ are supported. WiPy/CC3200: Bits can be 5, 6, 7, 8. Stop can be 1 or 2. -A UART object acts like a stream object and reading and writing is done +A UART object acts like a `stream` object and reading and writing is done using the standard stream methods:: uart.read(10) # read 10 characters, returns a bytes object diff --git a/docs/library/pyb.UART.rst b/docs/library/pyb.UART.rst index 76f347ffa8..c299c838e7 100644 --- a/docs/library/pyb.UART.rst +++ b/docs/library/pyb.UART.rst @@ -23,7 +23,7 @@ UART objects can be created and initialised using:: *Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled, only 7 and 8 bits are supported. -A UART object acts like a stream object and reading and writing is done +A UART object acts like a `stream` object and reading and writing is done using the standard stream methods:: uart.read(10) # read 10 characters, returns a bytes object diff --git a/docs/library/pyb.USB_VCP.rst b/docs/library/pyb.USB_VCP.rst index 80cc40cdde..3bc6c749ce 100644 --- a/docs/library/pyb.USB_VCP.rst +++ b/docs/library/pyb.USB_VCP.rst @@ -4,7 +4,7 @@ class USB_VCP -- USB virtual comm port ====================================== -The USB_VCP class allows creation of an object representing the USB +The USB_VCP class allows creation of a `stream`-like object representing the USB virtual comm port. It can be used to read and write data over USB to the connected host. @@ -47,7 +47,7 @@ Methods Read at most ``nbytes`` from the serial device and return them as a bytes object. If ``nbytes`` is not specified then the method reads all available bytes from the serial device. - USB_VCP stream implicitly works in non-blocking mode, + USB_VCP `stream` implicitly works in non-blocking mode, so if no pending data available, this method will return immediately with ``None`` value. diff --git a/docs/library/sys.rst b/docs/library/sys.rst index d49577306e..f2d96cb8cc 100644 --- a/docs/library/sys.rst +++ b/docs/library/sys.rst @@ -104,15 +104,15 @@ Constants .. data:: stderr - Standard error stream. + Standard error `stream`. .. data:: stdin - Standard input stream. + Standard input `stream`. .. data:: stdout - Standard output stream. + Standard output `stream`. .. data:: version diff --git a/docs/library/uio.rst b/docs/library/uio.rst index 7042a9e376..7e6c932284 100644 --- a/docs/library/uio.rst +++ b/docs/library/uio.rst @@ -6,7 +6,7 @@ |see_cpython_module| :mod:`python:io`. -This module contains additional types of stream (file-like) objects +This module contains additional types of `stream` (file-like) objects and helper functions. Conceptual hierarchy diff --git a/docs/library/uos.rst b/docs/library/uos.rst index 43bf69cc0a..c7fa4b3081 100644 --- a/docs/library/uos.rst +++ b/docs/library/uos.rst @@ -91,7 +91,7 @@ Functions .. function:: dupterm(stream_object, index=0) - Duplicate or switch the MicroPython terminal (the REPL) on the given stream-like + Duplicate or switch the MicroPython terminal (the REPL) on the given `stream`-like object. The *stream_object* argument must implement the ``readinto()`` and ``write()`` methods. The stream should be in non-blocking mode and ``readinto()`` should return ``None`` if there is no data available for reading. diff --git a/docs/library/uselect.rst b/docs/library/uselect.rst index f88ab7d1d9..fb43f7e63e 100644 --- a/docs/library/uselect.rst +++ b/docs/library/uselect.rst @@ -7,7 +7,7 @@ |see_cpython_module| :mod:`python:select`. This module provides functions to efficiently wait for events on multiple -streams (select streams which are ready for operations). +`streams ` (select streams which are ready for operations). Functions --------- @@ -33,7 +33,7 @@ Methods .. method:: poll.register(obj[, eventmask]) - Register *obj* for polling. *eventmask* is logical OR of: + Register `stream` *obj* for polling. *eventmask* is logical OR of: * `uselect.POLLIN` - data available for reading * `uselect.POLLOUT` - more data can be written diff --git a/docs/library/usocket.rst b/docs/library/usocket.rst index fab05b652b..de55fc14ca 100644 --- a/docs/library/usocket.rst +++ b/docs/library/usocket.rst @@ -12,7 +12,7 @@ This module provides access to the BSD socket interface. .. admonition:: Difference to CPython :class: attention - For efficiency and consistency, socket objects in MicroPython implement a stream + For efficiency and consistency, socket objects in MicroPython implement a `stream` (file-like) interface directly. In CPython, you need to convert a socket to a file-like object using `makefile()` method. This method is still supported by MicroPython (but is a no-op), so where compatibility with CPython matters, @@ -248,7 +248,7 @@ Methods Not every `MicroPython port` supports this method. A more portable and generic solution is to use `uselect.poll` object. This allows to wait on multiple objects at the same time (and not just on sockets, but on generic - stream objects which support polling). Example:: + `stream` objects which support polling). Example:: # Instead of: s.settimeout(1.0) # time in seconds diff --git a/docs/library/ussl.rst b/docs/library/ussl.rst index 3ec609f67b..903a351f4d 100644 --- a/docs/library/ussl.rst +++ b/docs/library/ussl.rst @@ -15,9 +15,9 @@ Functions .. function:: ussl.wrap_socket(sock, server_side=False, keyfile=None, certfile=None, cert_reqs=CERT_NONE, ca_certs=None) - Takes a stream *sock* (usually usocket.socket instance of ``SOCK_STREAM`` type), + Takes a `stream` *sock* (usually usocket.socket instance of ``SOCK_STREAM`` type), and returns an instance of ssl.SSLSocket, which wraps the underlying stream in - an SSL context. Returned object has the usual stream interface methods like + an SSL context. Returned object has the usual `stream` interface methods like `read()`, `write()`, etc. In MicroPython, the returned object does not expose socket interface and methods like `recv()`, `send()`. In particular, a server-side SSL socket should be created from a normal socket returned from diff --git a/docs/library/uzlib.rst b/docs/library/uzlib.rst index fb1746fe8e..0b399f228a 100644 --- a/docs/library/uzlib.rst +++ b/docs/library/uzlib.rst @@ -25,7 +25,7 @@ Functions .. class:: DecompIO(stream, wbits=0) - Create a stream wrapper which allows transparent decompression of + Create a `stream` wrapper which allows transparent decompression of compressed data in another *stream*. This allows to process compressed streams with data larger than available heap size. In addition to values described in :func:`decompress`, *wbits* may take values From 62b96147e6126961c5d1d6bb28b7ac7034fa9322 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 5 Dec 2017 00:38:41 +0200 Subject: [PATCH 081/828] py: mp_call_function_*_protected(): Pass-thru return value if possible. Return the result of called function. If exception happened, return MP_OBJ_NULL. Allows to use mp_call_function_*_protected() with callbacks returning values, etc. --- py/runtime.h | 5 +++-- py/runtime_utils.c | 12 ++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/py/runtime.h b/py/runtime.h index 9c1921cb5d..3f0d1104e1 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -106,8 +106,9 @@ mp_obj_t mp_call_method_n_kw(size_t n_args, size_t n_kw, const mp_obj_t *args); mp_obj_t mp_call_method_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_obj_t *args); mp_obj_t mp_call_method_self_n_kw(mp_obj_t meth, mp_obj_t self, size_t n_args, size_t n_kw, const mp_obj_t *args); // Call function and catch/dump exception - for Python callbacks from C code -void mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg); -void mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2); +// (return MP_OBJ_NULL in case of exception). +mp_obj_t mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg); +mp_obj_t mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2); typedef struct _mp_call_args_t { mp_obj_t fun; diff --git a/py/runtime_utils.c b/py/runtime_utils.c index a5c5403baf..b92c6bd767 100644 --- a/py/runtime_utils.c +++ b/py/runtime_utils.c @@ -27,22 +27,26 @@ #include "py/runtime.h" -void mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg) { +mp_obj_t mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg) { nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { - mp_call_function_1(fun, arg); + mp_obj_t ret = mp_call_function_1(fun, arg); nlr_pop(); + return ret; } else { mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + return MP_OBJ_NULL; } } -void mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2) { +mp_obj_t mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2) { nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { - mp_call_function_2(fun, arg1, arg2); + mp_obj_t ret = mp_call_function_2(fun, arg1, arg2); nlr_pop(); + return ret; } else { mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + return MP_OBJ_NULL; } } From e104e24e53a4e788785cca85332074b3cb5c6e29 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 5 Dec 2017 01:52:41 +0200 Subject: [PATCH 082/828] tests/run-tests: Wrap long lists to facilitate adding more items. --- tests/run-tests | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/run-tests b/tests/run-tests index a2efede0ae..08a92a14fa 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -50,7 +50,10 @@ def convert_regex_escapes(line): def run_micropython(pyb, args, test_file, is_special=False): - special_tests = ('micropython/meminfo.py', 'basics/bytes_compare3.py', 'basics/builtin_help.py', 'thread/thread_exc2.py') + special_tests = ( + 'micropython/meminfo.py', 'basics/bytes_compare3.py', + 'basics/builtin_help.py', 'thread/thread_exc2.py', + ) if pyb is None: # run on PC if test_file.startswith(('cmdline/', 'feature_check/')) or test_file in special_tests: @@ -477,7 +480,10 @@ def main(): test_dirs = ('basics', 'micropython', 'misc', 'extmod', 'wipy') else: # run PC tests - test_dirs = ('basics', 'micropython', 'float', 'import', 'io', 'misc', 'stress', 'unicode', 'extmod', 'unix', 'cmdline') + test_dirs = ( + 'basics', 'micropython', 'float', 'import', 'io', 'misc', + 'stress', 'unicode', 'extmod', 'unix', 'cmdline', + ) else: # run tests from these directories test_dirs = args.test_dirs From 58f00d7c0e116e17ab141ae18275edea14b88431 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 5 Dec 2017 12:14:57 +1100 Subject: [PATCH 083/828] py/modbuiltins: Use standard arg-parsing helper func for builtin print. This allows the function to raise an exception when unknown keyword args are passed in. This patch also reduces code size by (in bytes): bare-arm: -24 minimal x86: -76 unix x64: -56 unix nanbox: -84 stm32: -40 esp8266: -68 cc3200: -48 Furthermore, this patch adds space (" ") to the set of ROM qstrs which means it doesn't need to be put in RAM if it's ever used. --- py/modbuiltins.c | 58 ++++++++++++++++++++++++++---------------------- py/qstrdefs.h | 1 + 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/py/modbuiltins.c b/py/modbuiltins.c index 0c78832aca..c8e3235f6f 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -383,46 +383,52 @@ STATIC mp_obj_t mp_builtin_pow(size_t n_args, const mp_obj_t *args) { } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_pow_obj, 2, 3, mp_builtin_pow); -STATIC mp_obj_t mp_builtin_print(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { - mp_map_elem_t *sep_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_sep), MP_MAP_LOOKUP); - mp_map_elem_t *end_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_end), MP_MAP_LOOKUP); - const char *sep_data = " "; - size_t sep_len = 1; - const char *end_data = "\n"; - size_t end_len = 1; - if (sep_elem != NULL && sep_elem->value != mp_const_none) { - sep_data = mp_obj_str_get_data(sep_elem->value, &sep_len); - } - if (end_elem != NULL && end_elem->value != mp_const_none) { - end_data = mp_obj_str_get_data(end_elem->value, &end_len); - } - #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES - void *stream_obj = &mp_sys_stdout_obj; - mp_map_elem_t *file_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_file), MP_MAP_LOOKUP); - if (file_elem != NULL && file_elem->value != mp_const_none) { - stream_obj = MP_OBJ_TO_PTR(file_elem->value); // XXX may not be a concrete object - } +STATIC mp_obj_t mp_builtin_print(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sep, ARG_end, ARG_file }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sep, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR__space_)} }, + { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR__0x0a_)} }, + #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES + { MP_QSTR_file, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_sys_stdout_obj)} }, + #endif + }; - mp_print_t print = {stream_obj, mp_stream_write_adaptor}; + // parse args (a union is used to reduce the amount of C stack that is needed) + union { + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + size_t len[2]; + } u; + mp_arg_parse_all(0, NULL, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, u.args); + + #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES + // TODO file may not be a concrete object (eg it could be a small-int) + mp_print_t print = {MP_OBJ_TO_PTR(u.args[ARG_file].u_obj), mp_stream_write_adaptor}; #endif + + // extract the objects first because we are going to use the other part of the union + mp_obj_t sep = u.args[ARG_sep].u_obj; + mp_obj_t end = u.args[ARG_end].u_obj; + const char *sep_data = mp_obj_str_get_data(sep, &u.len[0]); + const char *end_data = mp_obj_str_get_data(end, &u.len[1]); + for (size_t i = 0; i < n_args; i++) { if (i > 0) { #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES - mp_stream_write_adaptor(stream_obj, sep_data, sep_len); + mp_stream_write_adaptor(print.data, sep_data, u.len[0]); #else - mp_print_strn(&mp_plat_print, sep_data, sep_len, 0, 0, 0); + mp_print_strn(&mp_plat_print, sep_data, u.len[0], 0, 0, 0); #endif } #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES - mp_obj_print_helper(&print, args[i], PRINT_STR); + mp_obj_print_helper(&print, pos_args[i], PRINT_STR); #else - mp_obj_print_helper(&mp_plat_print, args[i], PRINT_STR); + mp_obj_print_helper(&mp_plat_print, pos_args[i], PRINT_STR); #endif } #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES - mp_stream_write_adaptor(stream_obj, end_data, end_len); + mp_stream_write_adaptor(print.data, end_data, u.len[1]); #else - mp_print_strn(&mp_plat_print, end_data, end_len, 0, 0, 0); + mp_print_strn(&mp_plat_print, end_data, u.len[1], 0, 0, 0); #endif return mp_const_none; } diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 4ded5be084..1b480c9c75 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -40,6 +40,7 @@ Q(/) Q(%#o) Q(%#x) Q({:#b}) +Q( ) Q(\n) Q(maximum recursion depth exceeded) Q() From ca8034d6b888952dfb4401b867f5682ac683b5ff Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 6 Dec 2017 00:08:24 +0200 Subject: [PATCH 084/828] docs/glossary: Clarify wording for "baremetal". --- docs/reference/glossary.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/reference/glossary.rst b/docs/reference/glossary.rst index 98a2a50d8d..9daf0dc3a1 100644 --- a/docs/reference/glossary.rst +++ b/docs/reference/glossary.rst @@ -4,9 +4,10 @@ Glossary .. glossary:: baremetal - A system without (full-fledged) OS, like an :term:`MCU`. When - running on a baremetal system, MicroPython effectively becomes - its user-facing OS with a command interpreter (REPL). + A system without a (full-fledged) OS, for example an + :term:`MCU`-based system. When running on a baremetal system, + MicroPython effectively becomes its user-facing OS with a command + interpreter (REPL). board A PCB board. Oftentimes, the term is used to denote a particular From ccec4ee7ad1efe3cc794945cd172eb820046a543 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 6 Dec 2017 15:31:07 +0200 Subject: [PATCH 085/828] zephyr/CMakeLists.txt: Update for latest Zephyr buildsys changes. --- ports/zephyr/CMakeLists.txt | 8 ++++---- ports/zephyr/Makefile | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ports/zephyr/CMakeLists.txt b/ports/zephyr/CMakeLists.txt index cd7eda227c..b360a711df 100644 --- a/ports/zephyr/CMakeLists.txt +++ b/ports/zephyr/CMakeLists.txt @@ -7,10 +7,10 @@ add_library(libmicropython STATIC IMPORTED) set_target_properties(libmicropython PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/libmicropython.a) target_link_libraries(app libmicropython) -zephyr_get_include_directories_as_string(includes) -zephyr_get_system_include_directories_as_string(system_includes) -zephyr_get_compile_definitions_as_string(definitions) -zephyr_get_compile_options_as_string(options) +zephyr_get_include_directories_for_lang_as_string(C includes) +zephyr_get_system_include_directories_for_lang_as_string(C system_includes) +zephyr_get_compile_definitions_for_lang_as_string(C definitions) +zephyr_get_compile_options_for_lang_as_string(C options) add_custom_target( outputexports diff --git a/ports/zephyr/Makefile b/ports/zephyr/Makefile index d6d711d1c2..2064fcef7e 100644 --- a/ports/zephyr/Makefile +++ b/ports/zephyr/Makefile @@ -105,4 +105,4 @@ outdir/$(BOARD)/Makefile: $(CONF_FILE) $(Z_EXPORTS): outdir/$(BOARD)/Makefile make --no-print-directory -C outdir/$(BOARD) outputexports CMAKE_COMMAND=: >$@ - make -C outdir/$(BOARD) syscall_macros_h_target + make -C outdir/$(BOARD) syscall_macros_h_target syscall_list_h_target From ada1dc1c037371cd4680b00acff4bceaea511151 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 6 Dec 2017 16:45:27 +0200 Subject: [PATCH 086/828] zephyr/CMakeLists.txt: Properly separate CFLAGS parts gotten from CMake. Lack of spaces between them led to weird option artifacts like -Ifoo-Dbar. --- ports/zephyr/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr/CMakeLists.txt b/ports/zephyr/CMakeLists.txt index b360a711df..84b0e8190a 100644 --- a/ports/zephyr/CMakeLists.txt +++ b/ports/zephyr/CMakeLists.txt @@ -15,7 +15,7 @@ zephyr_get_compile_options_for_lang_as_string(C options) add_custom_target( outputexports COMMAND echo CC="${CMAKE_C_COMPILER}" - COMMAND echo Z_CFLAGS=${system_includes}${includes}${definitions}${options} + COMMAND echo Z_CFLAGS=${system_includes} ${includes} ${definitions} ${options} VERBATIM USES_TERMINAL ) From 5f8ad284f81c3f51be9b3d00ea9fee21ba727a97 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 7 Dec 2017 09:04:54 +0200 Subject: [PATCH 087/828] py/mpprint: Make "%p" format work properly on 64-bit systems. Before, the output was truncated to 32 bits. --- py/mpprint.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/py/mpprint.c b/py/mpprint.c index a569ef7931..74912eb5f9 100644 --- a/py/mpprint.c +++ b/py/mpprint.c @@ -512,7 +512,8 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { break; case 'p': case 'P': // don't bother to handle upcase for 'P' - chrs += mp_print_int(print, va_arg(args, unsigned int), 0, 16, 'a', flags, fill, width); + // Use unsigned long int to work on both ILP32 and LP64 systems + chrs += mp_print_int(print, va_arg(args, unsigned long int), 0, 16, 'a', flags, fill, width); break; #if MICROPY_PY_BUILTINS_FLOAT case 'e': From 5a10e63543cae424a71f93ea95b79d34df095832 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 7 Dec 2017 10:00:23 +0200 Subject: [PATCH 088/828] py/mpprint: Support "%lx" format on 64-bit systems. Before that, the output was truncated to 32 bits. Only "%x" format is handled, because a typical use is for addresses. This refactor actually decreased x86_64 code size by 30 bytes. --- py/mpprint.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/py/mpprint.c b/py/mpprint.c index 74912eb5f9..d6d9cf963c 100644 --- a/py/mpprint.c +++ b/py/mpprint.c @@ -446,11 +446,16 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { } } - // parse long specifiers (current not used) - //bool long_arg = false; + // parse long specifiers (only for LP64 model where they make a difference) + #ifndef __LP64__ + const + #endif + bool long_arg = false; if (*fmt == 'l') { ++fmt; - //long_arg = true; + #ifdef __LP64__ + long_arg = true; + #endif } if (*fmt == '\0') { @@ -505,11 +510,17 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { chrs += mp_print_int(print, va_arg(args, int), 1, 10, 'a', flags, fill, width); break; case 'x': - chrs += mp_print_int(print, va_arg(args, unsigned int), 0, 16, 'a', flags, fill, width); - break; - case 'X': - chrs += mp_print_int(print, va_arg(args, unsigned int), 0, 16, 'A', flags, fill, width); + case 'X': { + char fmt_c = 'x' - *fmt + 'A'; + mp_uint_t val; + if (long_arg) { + val = va_arg(args, unsigned long int); + } else { + val = va_arg(args, unsigned int); + } + chrs += mp_print_int(print, val, 0, 16, fmt_c, flags, fill, width); break; + } case 'p': case 'P': // don't bother to handle upcase for 'P' // Use unsigned long int to work on both ILP32 and LP64 systems From f5e097021ce95cf4398f89c4f4268efbc5717b89 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 7 Dec 2017 10:31:14 +0200 Subject: [PATCH 089/828] py/mpprint: Fix "%x" vs "%X" regression introduced in previous commit. --- py/mpprint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/mpprint.c b/py/mpprint.c index d6d9cf963c..c2e65301c9 100644 --- a/py/mpprint.c +++ b/py/mpprint.c @@ -511,7 +511,7 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { break; case 'x': case 'X': { - char fmt_c = 'x' - *fmt + 'A'; + char fmt_c = *fmt - 'X' + 'A'; mp_uint_t val; if (long_arg) { val = va_arg(args, unsigned long int); From 88a8043a27c3f75c7e4e52e4e8b0d47005cd6bef Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 7 Dec 2017 10:52:40 +0200 Subject: [PATCH 090/828] py/malloc: MICROPY_MEM_STATS requires MICROPY_MALLOC_USES_ALLOCATED_SIZE. Error out if they're set incompatibly. --- py/malloc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/py/malloc.c b/py/malloc.c index ea1d4c4b9e..818a3e57a9 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -39,6 +39,9 @@ #endif #if MICROPY_MEM_STATS +#if !MICROPY_MALLOC_USES_ALLOCATED_SIZE +#error MICROPY_MEM_STATS requires MICROPY_MALLOC_USES_ALLOCATED_SIZE +#endif #define UPDATE_PEAK() { if (MP_STATE_MEM(current_bytes_allocated) > MP_STATE_MEM(peak_bytes_allocated)) MP_STATE_MEM(peak_bytes_allocated) = MP_STATE_MEM(current_bytes_allocated); } #endif From 9ebc037eee575fd951dea92c82ed9704d9101924 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 7 Dec 2017 17:57:33 +0200 Subject: [PATCH 091/828] py/malloc: Allow to use debug logging if !MICROPY_MALLOC_USES_ALLOCATED_SIZE. This is mostly a workaround for forceful rebuilding of mpy-cross on every codebase change. If this file has debug logging enabled (by patching), mpy-cross build failed. --- py/malloc.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/py/malloc.c b/py/malloc.c index 818a3e57a9..6835ed7c99 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -147,7 +147,11 @@ void *m_realloc(void *ptr, size_t new_num_bytes) { MP_STATE_MEM(current_bytes_allocated) += diff; UPDATE_PEAK(); #endif + #if MICROPY_MALLOC_USES_ALLOCATED_SIZE DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, old_num_bytes, new_num_bytes, new_ptr); + #else + DEBUG_printf("realloc %p, %d : %p\n", ptr, new_num_bytes, new_ptr); + #endif return new_ptr; } @@ -171,7 +175,11 @@ void *m_realloc_maybe(void *ptr, size_t new_num_bytes, bool allow_move) { UPDATE_PEAK(); } #endif + #if MICROPY_MALLOC_USES_ALLOCATED_SIZE DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, old_num_bytes, new_num_bytes, new_ptr); + #else + DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, new_num_bytes, new_ptr); + #endif return new_ptr; } @@ -184,7 +192,11 @@ void m_free(void *ptr) { #if MICROPY_MEM_STATS MP_STATE_MEM(current_bytes_allocated) -= num_bytes; #endif + #if MICROPY_MALLOC_USES_ALLOCATED_SIZE DEBUG_printf("free %p, %d\n", ptr, num_bytes); + #else + DEBUG_printf("free %p\n", ptr); + #endif } #if MICROPY_MEM_STATS From 9ef4be8b41c7d256908ba319918c0f7d54346bf4 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 8 Dec 2017 00:10:44 +0200 Subject: [PATCH 092/828] py/gc: Add CLEAR_ON_SWEEP option to debug mis-traced objects. Accessing them will crash immediately instead still working for some time, until overwritten by some other data, leading to much less deterministic crashes. --- py/gc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/py/gc.c b/py/gc.c index 172a5e8fc0..9a3c57e619 100644 --- a/py/gc.c +++ b/py/gc.c @@ -44,6 +44,10 @@ // make this 1 to dump the heap each time it changes #define EXTENSIVE_HEAP_PROFILING (0) +// make this 1 to zero out swept memory to more eagerly +// detect untraced object still in use +#define CLEAR_ON_SWEEP (0) + #define WORDS_PER_BLOCK ((MICROPY_BYTES_PER_GC_BLOCK) / BYTES_PER_WORD) #define BYTES_PER_BLOCK (MICROPY_BYTES_PER_GC_BLOCK) @@ -286,6 +290,9 @@ STATIC void gc_sweep(void) { case AT_TAIL: if (free_tail) { ATB_ANY_TO_FREE(block); + #if CLEAR_ON_SWEEP + memset((void*)PTR_FROM_BLOCK(block), 0, BYTES_PER_BLOCK); + #endif } break; From f935bce3c52e8eb8f48f7f4947b1210074c359a6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 8 Dec 2017 18:23:23 +1100 Subject: [PATCH 093/828] py/{emitbc,asmbase}: Only clear emit labels to -1 when in debug mode. Clearing the labels to -1 is purely a debugging measure. For release builds there is no need to do it as the label offset table should always have the correct value assigned. --- py/asmbase.c | 4 +++- py/emitbc.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/py/asmbase.c b/py/asmbase.c index c941e917b7..83a699cd41 100644 --- a/py/asmbase.c +++ b/py/asmbase.c @@ -47,8 +47,10 @@ void mp_asm_base_deinit(mp_asm_base_t *as, bool free_code) { void mp_asm_base_start_pass(mp_asm_base_t *as, int pass) { if (pass == MP_ASM_PASS_COMPUTE) { - // reset all labels + #ifndef NDEBUG + // With debugging enabled labels are checked for unique assignment memset(as->label_offsets, -1, as->max_num_labels * sizeof(size_t)); + #endif } else if (pass == MP_ASM_PASS_EMIT) { // allocating executable RAM is platform specific MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size); diff --git a/py/emitbc.c b/py/emitbc.c index 3f4dfc1786..5e7fa623a3 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -313,9 +313,12 @@ void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { emit->scope = scope; emit->last_source_line_offset = 0; emit->last_source_line = 1; + #ifndef NDEBUG + // With debugging enabled labels are checked for unique assignment if (pass < MP_PASS_EMIT) { memset(emit->label_offsets, -1, emit->max_num_labels * sizeof(mp_uint_t)); } + #endif emit->bytecode_offset = 0; emit->code_info_offset = 0; @@ -495,7 +498,6 @@ void mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l) { emit->label_offsets[l] = emit->bytecode_offset; } else { // ensure label offset has not changed from MP_PASS_CODE_SIZE to MP_PASS_EMIT - //printf("l%d: (at %d vs %d)\n", l, emit->bytecode_offset, emit->label_offsets[l]); assert(emit->label_offsets[l] == emit->bytecode_offset); } } From 53e111800f9e53733042442eefea0ffc293a35df Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 8 Dec 2017 19:07:00 +1100 Subject: [PATCH 094/828] py/asmbase: Revert removal of clearing of label offsets for native emit. The assembler back-end for most architectures needs to know if a jump is backwards in order to emit optimised machine code, and they do this by checking if the destination label has been set or not. So always reset label offsets to -1 (this reverts partially the previous commit, with some minor optimisation for the if-logic with the pass variable). --- py/asmbase.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/py/asmbase.c b/py/asmbase.c index 83a699cd41..4c84c3b255 100644 --- a/py/asmbase.c +++ b/py/asmbase.c @@ -46,12 +46,10 @@ void mp_asm_base_deinit(mp_asm_base_t *as, bool free_code) { } void mp_asm_base_start_pass(mp_asm_base_t *as, int pass) { - if (pass == MP_ASM_PASS_COMPUTE) { - #ifndef NDEBUG - // With debugging enabled labels are checked for unique assignment + if (pass < MP_ASM_PASS_EMIT) { + // Reset labels so we can detect backwards jumps (and verify unique assignment) memset(as->label_offsets, -1, as->max_num_labels * sizeof(size_t)); - #endif - } else if (pass == MP_ASM_PASS_EMIT) { + } else { // allocating executable RAM is platform specific MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size); assert(as->code_base != NULL); From 55d33d5897b27dd4b70041a38674ff1bd55709a4 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 8 Dec 2017 12:39:57 +0200 Subject: [PATCH 095/828] zephyr/main: Move var declarations to the top of file. --- ports/zephyr/main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ports/zephyr/main.c b/ports/zephyr/main.c index 7eb9da3e12..d6ddc65cc2 100644 --- a/ports/zephyr/main.c +++ b/ports/zephyr/main.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2016 Linaro Limited + * Copyright (c) 2016-2017 Linaro Limited * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -41,6 +41,9 @@ #include "lib/utils/pyexec.h" #include "lib/mp-readline/readline.h" +static char *stack_top; +static char heap[MICROPY_HEAP_SIZE]; + void do_str(const char *src, mp_parse_input_kind_t input_kind) { nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { @@ -56,9 +59,6 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) { } } -static char *stack_top; -static char heap[MICROPY_HEAP_SIZE]; - void init_zephyr(void) { // We now rely on CONFIG_NET_APP_SETTINGS to set up bootstrap // network addresses. From 24c641c4e3637a8c73b7546c5500a49f7dd94b2a Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 8 Dec 2017 19:15:45 +0200 Subject: [PATCH 096/828] qemu-arm/test_main: Clean up invocation of tinytest_main(). Command-line argc and argv should be passed, and as we don't have them, placeholders were passed, but incorrectly. As we don't have them, just pass 0/NULL. Looking at the source, this migh lead to problems under Windows, but this test doesn't run under Windows. Also, use "%d" printf format consistently with the rest of the codebase. --- ports/qemu-arm/test_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ports/qemu-arm/test_main.c b/ports/qemu-arm/test_main.c index c018ae4285..acac66e6aa 100644 --- a/ports/qemu-arm/test_main.c +++ b/ports/qemu-arm/test_main.c @@ -49,12 +49,11 @@ end: #include "genhdr/tests.h" int main() { - const char a[] = {"sim"}; mp_stack_ctrl_init(); mp_stack_set_limit(10240); heap = malloc(HEAP_SIZE); - int r = tinytest_main(1, (const char **) a, groups); - printf( "status: %i\n", r); + int r = tinytest_main(0, NULL, groups); + printf("status: %d\n", r); return r; } From e9d29c9ba997ae0f00f16f3a21dffce7c763a3d4 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 8 Dec 2017 19:26:15 +0200 Subject: [PATCH 097/828] lib/tinytest: Move from tools/tinytest. Tinytest library was misplaced under tools/. By convention, any target libraries belong to lib/, while tools/ contains host-side tools. --- {tools => lib}/tinytest/README | 0 {tools => lib}/tinytest/tinytest.c | 0 {tools => lib}/tinytest/tinytest.h | 0 {tools => lib}/tinytest/tinytest_macros.h | 0 ports/qemu-arm/Makefile | 6 ++++-- 5 files changed, 4 insertions(+), 2 deletions(-) rename {tools => lib}/tinytest/README (100%) rename {tools => lib}/tinytest/tinytest.c (100%) rename {tools => lib}/tinytest/tinytest.h (100%) rename {tools => lib}/tinytest/tinytest_macros.h (100%) diff --git a/tools/tinytest/README b/lib/tinytest/README similarity index 100% rename from tools/tinytest/README rename to lib/tinytest/README diff --git a/tools/tinytest/tinytest.c b/lib/tinytest/tinytest.c similarity index 100% rename from tools/tinytest/tinytest.c rename to lib/tinytest/tinytest.c diff --git a/tools/tinytest/tinytest.h b/lib/tinytest/tinytest.h similarity index 100% rename from tools/tinytest/tinytest.h rename to lib/tinytest/tinytest.h diff --git a/tools/tinytest/tinytest_macros.h b/lib/tinytest/tinytest_macros.h similarity index 100% rename from tools/tinytest/tinytest_macros.h rename to lib/tinytest/tinytest_macros.h diff --git a/ports/qemu-arm/Makefile b/ports/qemu-arm/Makefile index 39e13853f4..c0d257a3eb 100644 --- a/ports/qemu-arm/Makefile +++ b/ports/qemu-arm/Makefile @@ -9,10 +9,12 @@ include $(TOP)/py/py.mk CROSS_COMPILE = arm-none-eabi- +TINYTEST = $(TOP)/lib/tinytest + INC += -I. INC += -I$(TOP) INC += -I$(BUILD) -INC += -I$(TOP)/tools/tinytest/ +INC += -I$(TINYTEST) CFLAGS_CORTEX_M3 = -mthumb -mcpu=cortex-m3 -mfloat-abi=soft CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 $(CFLAGS_CORTEX_M3) $(COPT) \ @@ -101,7 +103,7 @@ $(BUILD)/genhdr/tests.h: $(Q)echo "Generating $@";(cd $(TOP)/tests; ../tools/tinytest-codegen.py) > $@ $(BUILD)/tinytest.o: - $(Q)$(CC) $(CFLAGS) -DNO_FORKING -o $@ -c $(TOP)/tools/tinytest/tinytest.c + $(Q)$(CC) $(CFLAGS) -DNO_FORKING -o $@ -c $(TINYTEST)/tinytest.c ## `$(LD)` doesn't seem to like `--specs` for some reason, but we can just use `$(CC)` here. $(BUILD)/firmware.elf: $(OBJ_COMMON) $(OBJ_RUN) From c0877cbb0d51f66fa828f6df5698751210391296 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 8 Dec 2017 20:40:55 +0200 Subject: [PATCH 098/828] py/objint_longlong: Check for zero division/modulo. --- py/objint_longlong.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/py/objint_longlong.c b/py/objint_longlong.c index 2e567c5721..3e5ebadaf3 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -151,9 +151,15 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i return mp_obj_new_int_from_ll(lhs_val * rhs_val); case MP_BINARY_OP_FLOOR_DIVIDE: case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: + if (rhs_val == 0) { + goto zero_division; + } return mp_obj_new_int_from_ll(lhs_val / rhs_val); case MP_BINARY_OP_MODULO: case MP_BINARY_OP_INPLACE_MODULO: + if (rhs_val == 0) { + goto zero_division; + } return mp_obj_new_int_from_ll(lhs_val % rhs_val); case MP_BINARY_OP_AND: @@ -210,6 +216,9 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i default: return MP_OBJ_NULL; // op not supported } + +zero_division: + mp_raise_msg(&mp_type_ZeroDivisionError, "division by zero"); } mp_obj_t mp_obj_new_int(mp_int_t value) { From 39dd89fe3142478b48d7282b8b1bdff933c25f32 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 9 Dec 2017 01:26:21 +0200 Subject: [PATCH 099/828] py/runtime: When tracing unary/binary ops, output op (method) name. E.g.: >>> 1+1 binary 26 __add__ 3 3 Output is similar to bytecode dump (numeric code, then op name). --- py/runtime.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/py/runtime.c b/py/runtime.c index c7fe393675..457266c67f 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -214,7 +214,7 @@ void mp_delete_global(qstr qst) { } mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) { - DEBUG_OP_printf("unary " UINT_FMT " %p\n", op, arg); + DEBUG_OP_printf("unary " UINT_FMT " %q %p\n", op, mp_unary_op_method_name[op], arg); if (op == MP_UNARY_OP_NOT) { // "not x" is the negative of whether "x" is true per Python semantics @@ -275,7 +275,7 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) { } mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { - DEBUG_OP_printf("binary " UINT_FMT " %p %p\n", op, lhs, rhs); + DEBUG_OP_printf("binary " UINT_FMT " %q %p %p\n", op, mp_binary_op_method_name[op], lhs, rhs); // TODO correctly distinguish inplace operators for mutable objects // lookup logic that CPython uses for +=: From 5453d88d5db94e686cf26930e88a5e20fd21d8f8 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 9 Dec 2017 01:48:26 +0200 Subject: [PATCH 100/828] py/gc: Factor out a macro to trace GC mark operations. To allow easier override it for custom tracing. --- py/gc.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/py/gc.c b/py/gc.c index 9a3c57e619..1b99ab4cfa 100644 --- a/py/gc.c +++ b/py/gc.c @@ -195,6 +195,14 @@ bool gc_is_locked(void) { && ptr < (void*)MP_STATE_MEM(gc_pool_end) /* must be below end of pool */ \ ) +#ifndef TRACE_MARK +#if DEBUG_PRINT +#define TRACE_MARK(block, ptr) DEBUG_printf("gc_mark(%p)\n", ptr) +#else +#define TRACE_MARK(block, ptr) +#endif +#endif + // ptr should be of type void* #define VERIFY_MARK_AND_PUSH(ptr) \ do { \ @@ -202,7 +210,7 @@ bool gc_is_locked(void) { size_t _block = BLOCK_FROM_PTR(ptr); \ if (ATB_GET_KIND(_block) == AT_HEAD) { \ /* an unmarked head, mark it, and push it on gc stack */ \ - DEBUG_printf("gc_mark(%p)\n", ptr); \ + TRACE_MARK(_block, ptr); \ ATB_HEAD_TO_MARK(_block); \ if (MP_STATE_MEM(gc_sp) < &MP_STATE_MEM(gc_stack)[MICROPY_ALLOC_GC_STACK_SIZE]) { \ *MP_STATE_MEM(gc_sp)++ = _block; \ From dea3fb93c74ae61dc5168b62a780dc6ce7865e09 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 9 Dec 2017 01:54:01 +0200 Subject: [PATCH 101/828] py/gc: In sweep debug output, print pointer as a pointer. Or it will be truncated on a 64-bit platform. --- py/gc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/gc.c b/py/gc.c index 1b99ab4cfa..734f5c3648 100644 --- a/py/gc.c +++ b/py/gc.c @@ -289,7 +289,7 @@ STATIC void gc_sweep(void) { } #endif free_tail = 1; - DEBUG_printf("gc_sweep(%x)\n", PTR_FROM_BLOCK(block)); + DEBUG_printf("gc_sweep(%p)\n", PTR_FROM_BLOCK(block)); #if MICROPY_PY_GC_COLLECT_RETVAL MP_STATE_MEM(gc_collected)++; #endif From fca1d1aa62306fc523d192c1e2dd2d20dccbe94f Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 9 Dec 2017 09:19:34 +0200 Subject: [PATCH 102/828] py/objfun: Factor out macro for decoding codestate size. fun_bc_call() starts with almost the same code as mp_obj_fun_bc_prepare_codestate(), the only difference is a way to allocate the codestate object (heap vs stack with heap fallback). Still, would be nice to avoid code duplication to make further refactoring easier. So, this commit factors out the common code before the allocation - decoding and calculating codestate size. It produces two values, so structured as a macro which writes to 2 variables passed as arguments. --- py/objfun.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/py/objfun.c b/py/objfun.c index 030b3f7cb0..445f25d46b 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -195,20 +195,30 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) { // than this will try to use the heap, with fallback to stack allocation. #define VM_MAX_STATE_ON_STACK (11 * sizeof(mp_uint_t)) -// Set this to enable a simple stack overflow check. +// Set this to 1 to enable a simple stack overflow check. #define VM_DETECT_STACK_OVERFLOW (0) +#define DECODE_CODESTATE_SIZE(bytecode, n_state_out_var, state_size_out_var) \ + { \ + /* bytecode prelude: state size and exception stack size */ \ + n_state_out_var = mp_decode_uint_value(bytecode); \ + size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(bytecode)); \ + \ + n_state += VM_DETECT_STACK_OVERFLOW; \ + \ + /* state size in bytes */ \ + state_size_out_var = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t); \ + } + #if MICROPY_STACKLESS mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { MP_STACK_CHECK(); mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); - // bytecode prelude: state size and exception stack size - size_t n_state = mp_decode_uint_value(self->bytecode); - size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(self->bytecode)); + size_t n_state, state_size; + DECODE_CODESTATE_SIZE(self->bytecode, n_state, state_size); // allocate state for locals and stack - size_t state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t); mp_code_state_t *code_state; code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size); if (!code_state) { @@ -238,16 +248,10 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); DEBUG_printf("Func n_def_args: %d\n", self->n_def_args); - // bytecode prelude: state size and exception stack size - size_t n_state = mp_decode_uint_value(self->bytecode); - size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(self->bytecode)); - -#if VM_DETECT_STACK_OVERFLOW - n_state += 1; -#endif + size_t n_state, state_size; + DECODE_CODESTATE_SIZE(self->bytecode, n_state, state_size); // allocate state for locals and stack - size_t state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t); mp_code_state_t *code_state = NULL; if (state_size > VM_MAX_STATE_ON_STACK) { code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size); From d72370def72c74ca98c1ec4eb7b58ba0fbcc9629 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 9 Dec 2017 10:57:40 +0200 Subject: [PATCH 103/828] py/objfun, vm: Add comments on codestate allocation in stackless mode. --- py/objfun.c | 6 +++++- py/vm.c | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/py/objfun.c b/py/objfun.c index 445f25d46b..e27413e40a 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -218,8 +218,12 @@ mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args size_t n_state, state_size; DECODE_CODESTATE_SIZE(self->bytecode, n_state, state_size); - // allocate state for locals and stack mp_code_state_t *code_state; + // If we use m_new_obj_var(), then on no memory, MemoryError will be + // raised. But this is not correct exception for a function call, + // RuntimeError should be raised instead. So, we use m_new_obj_var_maybe(), + // return NULL, then vm.c takes the needed action (either raise + // RuntimeError or fallback to stack allocation). code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size); if (!code_state) { return NULL; diff --git a/py/vm.c b/py/vm.c index 564200037a..e6679729b2 100644 --- a/py/vm.c +++ b/py/vm.c @@ -937,6 +937,9 @@ unwind_jump:; deep_recursion_error: mp_exc_recursion_depth(); } + #else + // If we couldn't allocate codestate on heap, in + // non non-strict case fall thru to stack allocation. #endif } #endif @@ -974,6 +977,9 @@ unwind_jump:; else { goto deep_recursion_error; } + #else + // If we couldn't allocate codestate on heap, in + // non non-strict case fall thru to stack allocation. #endif } #endif @@ -1008,6 +1014,9 @@ unwind_jump:; else { goto deep_recursion_error; } + #else + // If we couldn't allocate codestate on heap, in + // non non-strict case fall thru to stack allocation. #endif } #endif @@ -1045,6 +1054,9 @@ unwind_jump:; else { goto deep_recursion_error; } + #else + // If we couldn't allocate codestate on heap, in + // non non-strict case fall thru to stack allocation. #endif } #endif From 2b00181592b23e5ca97464791c1ffa56e9495489 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 9 Dec 2017 12:45:28 +0200 Subject: [PATCH 104/828] py/objfun: Factor out macro for initializing codestate. This is second part of fun_bc_call() vs mp_obj_fun_bc_prepare_codestate() common code refactor. This factors out code to initialize codestate object. After this patch, mp_obj_fun_bc_prepare_codestate() is effectively DECODE_CODESTATE_SIZE() followed by allocation followed by INIT_CODESTATE(), and fun_bc_call() starts with that too. --- py/objfun.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/py/objfun.c b/py/objfun.c index e27413e40a..8fb3ec6fa2 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -210,6 +210,12 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) { state_size_out_var = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t); \ } +#define INIT_CODESTATE(code_state, _fun_bc, n_args, n_kw, args) \ + code_state->fun_bc = _fun_bc; \ + code_state->ip = 0; \ + mp_setup_code_state(code_state, n_args, n_kw, args); \ + code_state->old_globals = mp_globals_get(); + #if MICROPY_STACKLESS mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { MP_STACK_CHECK(); @@ -229,12 +235,9 @@ mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args return NULL; } - code_state->fun_bc = self; - code_state->ip = 0; - mp_setup_code_state(code_state, n_args, n_kw, args); + INIT_CODESTATE(code_state, self, n_args, n_kw, args); // execute the byte code with the correct globals context - code_state->old_globals = mp_globals_get(); mp_globals_set(self->globals); return code_state; @@ -265,12 +268,9 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const state_size = 0; // indicate that we allocated using alloca } - code_state->fun_bc = self; - code_state->ip = 0; - mp_setup_code_state(code_state, n_args, n_kw, args); + INIT_CODESTATE(code_state, self, n_args, n_kw, args); // execute the byte code with the correct globals context - code_state->old_globals = mp_globals_get(); mp_globals_set(self->globals); mp_vm_return_kind_t vm_return_kind = mp_execute_bytecode(code_state, MP_OBJ_NULL); mp_globals_set(code_state->old_globals); From a35d923cdf5a94ef9a29645f9dd461479dc819ce Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 9 Dec 2017 17:30:55 +0200 Subject: [PATCH 105/828] py/map: Allow to trace rehashing operations. --- py/map.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/py/map.c b/py/map.c index 4f76b9b16c..696c7a2ea2 100644 --- a/py/map.c +++ b/py/map.c @@ -33,6 +33,13 @@ #include "py/misc.h" #include "py/runtime.h" +#if MICROPY_DEBUG_VERBOSE // print debugging info +#define DEBUG_PRINT (1) +#else // don't print debugging info +#define DEBUG_PRINT (0) +#define DEBUG_printf(...) (void)0 +#endif + // Fixed empty map. Useful when need to call kw-receiving functions // without any keywords from C, etc. const mp_map_t mp_const_empty_map = { @@ -114,6 +121,7 @@ void mp_map_clear(mp_map_t *map) { STATIC void mp_map_rehash(mp_map_t *map) { size_t old_alloc = map->alloc; size_t new_alloc = get_hash_alloc_greater_or_equal_to(map->alloc + 1); + DEBUG_printf("mp_map_rehash(%p): " UINT_FMT " -> " UINT_FMT "\n", map, old_alloc, new_alloc); mp_map_elem_t *old_table = map->table; mp_map_elem_t *new_table = m_new0(mp_map_elem_t, new_alloc); // If we reach this point, table resizing succeeded, now we can edit the old map. From d21d029d55ddc026fcaf6673f2b712a645286dce Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 10 Dec 2017 01:05:29 +0200 Subject: [PATCH 106/828] py/mkrules.mk: Add "clean-frozen" target to clean frozen script/modules dir. This target removes any stray files (i.e. something not committed to git) from scripts/ and modules/ dirs (or whatever FROZEN_DIR and FROZEN_MPY_DIR is set to). The expected workflow is: 1. make clean-frozen 2. micropython -m upip -p modules 3. make As it can be expected that people may drop random thing in those dirs which they can miss later, the content is actually backed up before cleaning. --- py/mkrules.mk | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/py/mkrules.mk b/py/mkrules.mk index 72a5c3de06..96f6e35a64 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -160,6 +160,27 @@ clean: $(RM) -rf $(BUILD) $(CLEAN_EXTRA) .PHONY: clean +# Clean every non-git file from FROZEN_DIR/FROZEN_MPY_DIR, but making a backup. +# We run rmdir below to avoid empty backup dir (it will silently fail if backup +# is non-empty). +clean-frozen: + if [ -n "$(FROZEN_MPY_DIR)" ]; then \ + backup_dir=$(FROZEN_MPY_DIR).$$(date +%Y%m%dT%H%M%S); mkdir $$backup_dir; \ + cd $(FROZEN_MPY_DIR); git status --ignored -u all -s . | awk ' {print $$2}' \ + | xargs --no-run-if-empty cp --parents -t ../$$backup_dir; \ + rmdir ../$$backup_dir 2>/dev/null || true; \ + git clean -d -f .; \ + fi + + if [ -n "$(FROZEN_DIR)" ]; then \ + backup_dir=$(FROZEN_DIR).$$(date +%Y%m%dT%H%M%S); mkdir $$backup_dir; \ + cd $(FROZEN_DIR); git status --ignored -u all -s . | awk ' {print $$2}' \ + | xargs --no-run-if-empty cp --parents -t ../$$backup_dir; \ + rmdir ../$$backup_dir 2>/dev/null || true; \ + git clean -d -f .; \ + fi +.PHONY: clean-frozen + print-cfg: $(ECHO) "PY_SRC = $(PY_SRC)" $(ECHO) "BUILD = $(BUILD)" From e7fc765880ba6025ac5677db696669f43975483e Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 10 Dec 2017 02:15:43 +0200 Subject: [PATCH 107/828] unix/mpconfigport: Disable uio.resource_stream(). This function was implemented as an experiment, and was enabled only in unix port. To remind, it allows to access arbitrary files frozen as source modules (vs bytecode). However, further experimentation showed that the same functionality can be implemented with frozen bytecode. The process requires more steps, but with suitable toolset it doesn't matter patch. This process is: 1. Convert binary files into "Python resource module" with tools/mpy_bin2res.py. 2. Freeze as the bytecode. 3. Use micropython-lib's pkg_resources.resource_stream() to access it. In other words, the extra step is using tools/mpy_bin2res.py (because there would be wrapper for uio.resource_stream() anyway). Going frozen bytecode route allows more flexibility, and same/additional efficiency: 1. Frozen source support can be disabled altogether for additional code savings. 2. Resources could be also accessed as a buffer, not just as a stream. There're few caveats too: 1. It wasn't actually profiled the overhead of storing a resource in "Python resource module" vs storing it directly, but it's assumed that overhead is small. 2. The "efficiency" claim above applies to the case when resource file is frozen as the bytecode. If it's not, it actually will take a lot of RAM on loading. But in this case, the resource file should not be used (i.e. generated) in the first place, and micropython-lib's pkg_resources.resource_stream() implementation has the appropriate fallback to read the raw files instead. This still poses some distribution issues, e.g. to deployable to baremetal ports (which almost certainly would require freezeing as the bytecode), a distribution package should include the resource module. But for non-freezing deployment, presense of resource module will lead to memory inefficiency. All the discussion above reminds why uio.resource_stream() was implemented in the first place - to address some of the issues above. However, since then, frozen bytecode approach seems to prevail, so, while there're still some issues to address with it, this change is being made. This change saves 488 bytes for the unix x86_64 port. --- ports/unix/mpconfigport.h | 1 - py/mpconfig.h | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index a3d2bb7dbd..06ae1e2343 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -103,7 +103,6 @@ #endif #define MICROPY_PY_CMATH (1) #define MICROPY_PY_IO_FILEIO (1) -#define MICROPY_PY_IO_RESOURCE_STREAM (1) #define MICROPY_PY_GC_COLLECT_RETVAL (1) #define MICROPY_MODULE_FROZEN_STR (1) diff --git a/py/mpconfig.h b/py/mpconfig.h index 095b7ef7b9..7784367085 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -938,7 +938,11 @@ typedef double mp_float_t; // Whether to provide "uio.resource_stream()" function with // the semantics of CPython's pkg_resources.resource_stream() -// (allows to access resources in frozen packages). +// (allows to access binary resources in frozen source packages). +// Note that the same functionality can be achieved in "pure +// Python" by prepocessing binary resources into Python source +// and bytecode-freezing it (with a simple helper module available +// e.g. in micropython-lib). #ifndef MICROPY_PY_IO_RESOURCE_STREAM #define MICROPY_PY_IO_RESOURCE_STREAM (0) #endif From c60fc670ea9c2f525e16bb5a175db077b71b93e6 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 11 Dec 2017 00:06:38 +0200 Subject: [PATCH 108/828] docs/reference/packages: Add chapter on distribution packages and deployment. A long overdue overview of preparing packages, installing them with upip, freezing, dealing with resources. Initial version, more iterations required. --- docs/reference/index.rst | 1 + docs/reference/packages.rst | 274 ++++++++++++++++++++++++++++++++++++ 2 files changed, 275 insertions(+) create mode 100644 docs/reference/packages.rst diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 4d822d6fa6..9c5c164f3f 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -24,6 +24,7 @@ implementation and the best practices to use them. isr_rules.rst speed_python.rst constrained.rst + packages.rst .. only:: port_pyboard diff --git a/docs/reference/packages.rst b/docs/reference/packages.rst new file mode 100644 index 0000000000..28f5f9f487 --- /dev/null +++ b/docs/reference/packages.rst @@ -0,0 +1,274 @@ +Distribution packages, package management, and deploying applications +===================================================================== + +Just as the "big" Python, MicroPython supports creation of "third party" +packages, distributing them, and easily installing them in each user's +environment. This chapter discusses how these actions are achieved. +Some familiarity with Python packaging is recommended. + +Overview +-------- + +Steps below represent a high-level workflow when creating and consuming +packages: + +1. Python modules and packages are turned into distribution package + archives, and published at the Python Package Index (PyPI). +2. `upip` package manager can be used to install a distribution package + on a `MicroPython port` with networking capabilities (for example, + on the Unix port). +3. For ports without networking capabilities, an "installation image" + can be prepared on the Unix port, and transferred to a device by + suitable means. +4. For low-memory ports, the installation image can be frozen as the + bytecode into MicroPython executable, thus minimizing the memory + storage overheads. + +The sections below describe this process in details. + +Distribution packages +--------------------- + +Python modules and packages can be packaged into archives suitable for +transfer between systems, storing at the well-known location (PyPI), +and downloading on demand for deployment. These archives are known as +*distribution packages* (to differentiate them from Python packages +(means to organize Python source code)). + +The MicroPython distribution package format is a well-known tar.gz +format, with some adaptations however. The Gzip compressor, used as +an external wrapper for TAR archives, by default uses 32KB dictionary +size, which means that to uncompress a compressed stream, 32KB of +contguous memory needs to be allocated. This requirement may be not +satisfiable on low-memory devices, which may have total memory available +less than that amount, and even if not, a contiguous block like that +may be hard to allocate due to `memory fragmentation`. To accommodate +these constraints, MicroPython distribution packages use Gzip compression +with the dictionary size of 4K, which should be a suitable compromise +with still achieving some compression while being able to uncompressed +even by the smallest devices. + +Besides the small compression dictionary size, MicroPython distribution +packages also have other optimizations, like removing any files from +the archive which aren't used by the installation process. In particular, +`upip` package manager doesn't execute ``setup.py`` during installation +(see below), and thus that file is not included in the archive. + +At the same time, these optimizations make MicroPython distribution +packages not compatible with `CPython`'s package manager, ``pip``. +This isn't considered a big problem, because: + +1. Packages can be installed with `upip`, and then can be used with + CPython (if they are compatible with it). +2. In the other direction, majority of CPython packages would be + incompatible with MicroPython by various reasons, first of all, + the reliance on features not implemented by MicroPython. + +Summing up, the MicroPython distribution package archives are highly +optimized for MicroPython's target environments, which are highly +resource constrained devices. + + +``upip`` package manager +------------------------ + +MicroPython distribution packages are intended to be installed using +the `upip` package manager. `upip` is a Python application which is +usually distributed (as frozen bytecode) with network-enabled +`MicroPython ports `. At the very least, +`upip` is available in the `MicroPython Unix port`. + +On any `MicroPython port` providing `upip`, it can be accessed as +following:: + + import upip + upip.help() + upip.install(package_or_package_list, [path]) + +Where *package_or_package_list* is the name of a distribution +package to install, or a list of such names to install multiple +packages. Optional *path* parameter specifies filesystem +location to install under and defaults to the standard library +location (see below). + +An example of installing a specific package and then using it:: + + >>> import upip + >>> upip.install("micropython-pystone_lowmem") + [...] + >>> import pystone_lowmem + >>> pystone_lowmem.main() + +Note that the name of Python package and the name of distribution +package for it in general don't have to match, and oftentimes they +don't. This is because PyPI provides a central package repository +for all different Python implementations and versions, and thus +distribution package names may need to be namespaced for a particular +implementation. For example, all packages from `micropython-lib` +follow this naming convention: for a Python module or package named +``foo``, the distribution package name is ``micropython-foo``. + +For the ports which run MicroPython executable from the OS command +prompts (like the Unix port), `upip` can be (and indeed, usually is) +run from the command line instead of MicroPython's own REPL. The +commands which corresponds to the example above are:: + + micropython -m upip -h + micropython -m upip install [-p ] ... + micropython -m upip install micropython-pystone_lowmem + +[TODO: Describe installation path.] + + +Cross-installing packages +------------------------- + +For `MicroPython ports ` without native networking +capabilities, the recommend process is "cross-installing" them into a +"directory image" using the `MicroPython Unix port`, and then +transferring this image to a device by suitable means. + +Installing to a directory image involves using ``-p`` switch to `upip`:: + + micropython -m upip install -p install_image micropython-pystone_lowmem + +After this command, the package content (and contents of every depenency +packages) will be available in the ``install_image/`` subdirectory. You +would need to transfer contents of this directory (without the +``install_image/`` prefix) to the device, at the suitable location, where +it can be found by the Python ``import`` statement (see discussion of +the `upip` installation path above). + + +Cross-installing packages with freezing +--------------------------------------- + +For the low-memory `MicroPython ports `, the process +described in the previous section does not provide the most efficient +resource usage,because the packages are installed in the source form, +so need to be compiled to the bytecome on each import. This compilation +requires RAM, and the resulting bytecode is also stored in RAM, reducing +its amount available for storing application data. Moreover, the process +above requires presence of the filesystem on a device, and the most +resource-constrained devices may not even have it. + +The bytecode freezing is a process which resolves all the issues +mentioned above: + +* The source code is pre-compiled into bytecode and store as such. +* The bytecode is stored in ROM, not RAM. +* Filesystem is not required for frozen packages. + +Using frozen bytecode requires building the executable (firmware) +for a given `MicroPython port` from the C source code. Consequently, +the process is: + +1. Follow the instructions for a particular port on setting up a + toolchain and building the port. For example, for ESP8266 port, + study instructions in ``ports/esp8266/README.md`` and follow them. + Make sure you can build the port and deploy the resulting + executable/firmware successfully before proceeding to the next steps. +2. Build `MicroPython Unix port` and make sure it is in your PATH and + you can execute ``micropython``. +3. Change to port's directory (e.g. ``ports/esp8266/`` for ESP8266). +4. Run ``make clean-frozen``. This step cleans up any previous + modules which were installed for freezing (consequently, you need + to skip this step to add additional modules, instead of starting + from scratch). +5. Run ``micropython -m upip install -p modules ...`` to + install packages you want to freeze. +6. Run ``make clean``. +7. Run ``make``. + +After this, you should have the executable/firmware with modules as +the bytecode inside, which you can deploy the usual way. + +Few notes: + +1. Step 5 in the sequence above assumes that the distribution package + is available from PyPI. If that is not the case, you would need + to copy Python source files manually to ``modules/`` subdirectory + of the port port directory. (Note that upip does not support + installing from e.g. version control repositories). +2. The firmware for baremetal devices usually has size restrictions, + so adding too many frozen modules may overflow it. Usually, you + would get a linking error if this happens. However, in some cases, + an image may be produced, which is not runnable on a device. Such + cases are in general bugs, and should be reported and further + investigated. If you face such a situation, as an initial step, + you may want to decrease the amount of frozen modules included. + + +Application resources +--------------------- + +A complete application, besides the source code, oftentimes also consists +of data files, e.g. web page templates, game images, etc. It's clear how +to deal with those when application is installed manually - you just put +those data files in the filesystem at some location and use the normal +file access functions. + +The situation is different when deploying applications from packages - this +is more advanced, streamlined and flexible way, but also requires more +advanced approach to accessing data files. This approach is treating +the data files as "resources", and abstracting away access to them. + +Python supports resource access using its "setuptools" library, using +``pkg_resources`` module. MicroPython, following its usual approach, +implements subset of the functionality of that module, specifically +`pkg_resources.resource_stream(package, resource)` function. +The idea is that an application calls this function, passing a +resource identifier, which is a relative path to data file within +the specified package (usually top-level application package). It +returns a stream object which can be used to access resource contents. +Thus, the ``resource_stream()`` emulates interface of the standard +`open()` function. + +Implementation-wise, ``resource_stream()`` uses file operations +underlyingly, if distribution package is install in the filesystem. +However, it also supports functioning without the underlying filesystem, +e.g. if the package is frozen as the bytecode. This however requires +an extra intermediate step when packaging application - creation of +"Python resource module". + +The idea of this module is to convert binary data to a Python bytes +object, and put it into the dictionary, indexed by the resource name. +This conversion is done using ``tools/mpy_bin2res.py`` script from +the MicroPython distribution. + +Let's trace the complete process using the following example. Suppose +your application has the following structure:: + + my_app/ + __main__.py + utils.py + data/ + page.html + image.png + +``__main__.py`` and ``utils.py`` should access resources using the +following calls:: + + import pkg_resources + + pkg_resources.resource_stream(__name__, "data/page.html") + pkg_resources.resource_stream(__name__, "data/image.png") + +You can develop and debug using the `MicroPython Unix port` as usual. +When times come to make a distribution package out of it, you would +need to run following command, with ``my_app/`` being the current +directory (and assuming ``mpy_bin2res.py`` is in your path):: + + mpy_bin2res.py data/page.html data/image.png + +This will produce a Python resource module named ``R.py``. Afterwards, +you package the project for distribution as usual (using ``setup.py sdist``). +Prepared like this, your application will work both when deployed to +filesystem and as frozen bytecode. + +References +---------- + +* Python Packaging User Guide: https://packaging.python.org/ +* Setuptools documentation: https://setuptools.readthedocs.io/ +* Distutils documentation: https://docs.python.org/3/library/distutils.html From 5b8998da6dfed6c8f54b8b34228f25d93dbb9d29 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 20 Nov 2017 17:29:58 +1100 Subject: [PATCH 109/828] py/runtime: Move mp_exc_recursion_depth to runtime and rename to raise. For consistency this helper function is renamed to match the other exception helpers, and moved to their location in runtime.c. --- py/runtime.c | 7 +++++++ py/runtime.h | 2 +- py/stackctrl.c | 7 +------ py/vm.c | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/py/runtime.c b/py/runtime.c index 457266c67f..5fd053e1a2 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1456,3 +1456,10 @@ NORETURN void mp_raise_OSError(int errno_) { NORETURN void mp_raise_NotImplementedError(const char *msg) { mp_raise_msg(&mp_type_NotImplementedError, msg); } + +#if MICROPY_STACK_CHECK +NORETURN void mp_raise_recursion_depth(void) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError, + MP_OBJ_NEW_QSTR(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded))); +} +#endif diff --git a/py/runtime.h b/py/runtime.h index 3f0d1104e1..a19f64c067 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -151,7 +151,7 @@ NORETURN void mp_raise_ValueError(const char *msg); NORETURN void mp_raise_TypeError(const char *msg); NORETURN void mp_raise_NotImplementedError(const char *msg); NORETURN void mp_raise_OSError(int errno_); -NORETURN void mp_exc_recursion_depth(void); +NORETURN void mp_raise_recursion_depth(void); #if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG #undef mp_check_self diff --git a/py/stackctrl.c b/py/stackctrl.c index 11165b9a6f..5c07796bde 100644 --- a/py/stackctrl.c +++ b/py/stackctrl.c @@ -48,14 +48,9 @@ void mp_stack_set_limit(mp_uint_t limit) { MP_STATE_THREAD(stack_limit) = limit; } -NORETURN void mp_exc_recursion_depth(void) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError, - MP_OBJ_NEW_QSTR(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded))); -} - void mp_stack_check(void) { if (mp_stack_usage() >= MP_STATE_THREAD(stack_limit)) { - mp_exc_recursion_depth(); + mp_raise_recursion_depth(); } } diff --git a/py/vm.c b/py/vm.c index e6679729b2..5011af5c3e 100644 --- a/py/vm.c +++ b/py/vm.c @@ -935,7 +935,7 @@ unwind_jump:; #if MICROPY_STACKLESS_STRICT else { deep_recursion_error: - mp_exc_recursion_depth(); + mp_raise_recursion_depth(); } #else // If we couldn't allocate codestate on heap, in From 02d830c035aca166d70551e485ccd2d1658189c9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 26 Nov 2017 23:28:40 +1100 Subject: [PATCH 110/828] py: Introduce a Python stack for scoped allocation. This patch introduces the MICROPY_ENABLE_PYSTACK option (disabled by default) which enables a "Python stack" that allows to allocate and free memory in a scoped, or Last-In-First-Out (LIFO) way, similar to alloca(). A new memory allocation API is introduced along with this Py-stack. It includes both "local" and "nonlocal" LIFO allocation. Local allocation is intended to be equivalent to using alloca(), whereby the same function must free the memory. Nonlocal allocation is where another function may free the memory, so long as it's still LIFO. Follow-up patches will convert all uses of alloca() and VLA to the new scoped allocation API. The old behaviour (using alloca()) will still be available, but when MICROPY_ENABLE_PYSTACK is enabled then alloca() is no longer required or used. The benefits of enabling this option are (or will be once subsequent patches are made to convert alloca()/VLA): - Toolchains without alloca() can use this feature to obtain correct and efficient scoped memory allocation (compared to using the heap instead of alloca(), which is slower). - Even if alloca() is available, enabling the Py-stack gives slightly more efficient use of stack space when calling nested Python functions, due to the way that compilers implement alloca(). - Enabling the Py-stack with the stackless mode allows for even more efficient stack usage, as well as retaining high performance (because the heap is no longer used to build and destroy stackless code states). - With Py-stack and stackless enabled, Python-calling-Python is no longer recursive in the C mp_execute_bytecode function. The micropython.pystack_use() function is included to measure usage of the Python stack. --- py/gc.c | 7 +++ py/modmicropython.c | 10 ++++ py/modthread.c | 6 +++ py/mpconfig.h | 11 ++++ py/mpstate.h | 6 +++ py/nlr.h | 19 ++++++- py/nlrsetjmp.c | 1 + py/nlrthumb.c | 2 + py/nlrx64.c | 2 + py/nlrx86.c | 2 + py/nlrxtensa.c | 2 + py/py.mk | 1 + py/pystack.c | 56 ++++++++++++++++++++ py/pystack.h | 123 ++++++++++++++++++++++++++++++++++++++++++++ py/runtime.c | 2 +- py/runtime.h | 1 + 16 files changed, 249 insertions(+), 2 deletions(-) create mode 100644 py/pystack.c create mode 100644 py/pystack.h diff --git a/py/gc.c b/py/gc.c index 734f5c3648..5196954e2e 100644 --- a/py/gc.c +++ b/py/gc.c @@ -320,11 +320,18 @@ void gc_collect_start(void) { #endif MP_STATE_MEM(gc_stack_overflow) = 0; MP_STATE_MEM(gc_sp) = MP_STATE_MEM(gc_stack); + // Trace root pointers. This relies on the root pointers being organised // correctly in the mp_state_ctx structure. We scan nlr_top, dict_locals, // dict_globals, then the root pointer section of mp_state_vm. void **ptrs = (void**)(void*)&mp_state_ctx; gc_collect_root(ptrs, offsetof(mp_state_ctx_t, vm.qstr_last_chunk) / sizeof(void*)); + + #if MICROPY_ENABLE_PYSTACK + // Trace root pointers from the Python stack. + ptrs = (void**)(void*)MP_STATE_THREAD(pystack_start); + gc_collect_root(ptrs, (MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start)) / sizeof(void*)); + #endif } void gc_collect_root(void **ptrs, size_t len) { diff --git a/py/modmicropython.c b/py/modmicropython.c index 2aac53adc7..c14a0177de 100644 --- a/py/modmicropython.c +++ b/py/modmicropython.c @@ -112,6 +112,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_stack_use_obj, mp_micropython_st #endif // MICROPY_PY_MICROPYTHON_MEM_INFO +#if MICROPY_ENABLE_PYSTACK +STATIC mp_obj_t mp_micropython_pystack_use(void) { + return MP_OBJ_NEW_SMALL_INT(mp_pystack_usage()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_pystack_use_obj, mp_micropython_pystack_use); +#endif + #if MICROPY_ENABLE_GC STATIC mp_obj_t mp_micropython_heap_lock(void) { gc_lock(); @@ -167,6 +174,9 @@ STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = { #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0) { MP_ROM_QSTR(MP_QSTR_alloc_emergency_exception_buf), MP_ROM_PTR(&mp_alloc_emergency_exception_buf_obj) }, #endif + #if MICROPY_ENABLE_PYSTACK + { MP_ROM_QSTR(MP_QSTR_pystack_use), MP_ROM_PTR(&mp_micropython_pystack_use_obj) }, + #endif #if MICROPY_ENABLE_GC { MP_ROM_QSTR(MP_QSTR_heap_lock), MP_ROM_PTR(&mp_micropython_heap_lock_obj) }, { MP_ROM_QSTR(MP_QSTR_heap_unlock), MP_ROM_PTR(&mp_micropython_heap_unlock_obj) }, diff --git a/py/modthread.c b/py/modthread.c index cb071d0f86..61ada50351 100644 --- a/py/modthread.c +++ b/py/modthread.c @@ -165,6 +165,12 @@ STATIC void *thread_entry(void *args_in) { mp_stack_set_top(&ts + 1); // need to include ts in root-pointer scan mp_stack_set_limit(args->stack_size); + #if MICROPY_ENABLE_PYSTACK + // TODO threading and pystack is not fully supported, for now just make a small stack + mp_obj_t mini_pystack[128]; + mp_pystack_init(mini_pystack, &mini_pystack[128]); + #endif + // set locals and globals from the calling context mp_locals_set(args->dict_locals); mp_globals_set(args->dict_globals); diff --git a/py/mpconfig.h b/py/mpconfig.h index 7784367085..96cd8c651a 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -441,6 +441,17 @@ #define MICROPY_ENABLE_FINALISER (0) #endif +// Whether to enable a separate allocator for the Python stack. +// If enabled then the code must call mp_pystack_init before mp_init. +#ifndef MICROPY_ENABLE_PYSTACK +#define MICROPY_ENABLE_PYSTACK (0) +#endif + +// Number of bytes that memory returned by mp_pystack_alloc will be aligned by. +#ifndef MICROPY_PYSTACK_ALIGN +#define MICROPY_PYSTACK_ALIGN (8) +#endif + // Whether to check C stack usage. C stack used for calling Python functions, // etc. Not checking means segfault on overflow. #ifndef MICROPY_STACK_CHECK diff --git a/py/mpstate.h b/py/mpstate.h index 6a39ebdea9..d3b53f9151 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -224,6 +224,12 @@ typedef struct _mp_state_thread_t { #if MICROPY_STACK_CHECK size_t stack_limit; #endif + + #if MICROPY_ENABLE_PYSTACK + uint8_t *pystack_start; + uint8_t *pystack_end; + uint8_t *pystack_cur; + #endif } mp_state_thread_t; // This structure combines the above 3 structures. diff --git a/py/nlr.h b/py/nlr.h index 63fe392d9e..1235f14609 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -62,15 +62,32 @@ struct _nlr_buf_t { #if MICROPY_NLR_SETJMP jmp_buf jmpbuf; #endif + + #if MICROPY_ENABLE_PYSTACK + void *pystack; + #endif }; +// Helper macros to save/restore the pystack state +#if MICROPY_ENABLE_PYSTACK +#define MP_NLR_SAVE_PYSTACK(nlr_buf) (nlr_buf)->pystack = MP_STATE_THREAD(pystack_cur) +#define MP_NLR_RESTORE_PYSTACK(nlr_buf) MP_STATE_THREAD(pystack_cur) = (nlr_buf)->pystack +#else +#define MP_NLR_SAVE_PYSTACK(nlr_buf) (void)nlr_buf +#define MP_NLR_RESTORE_PYSTACK(nlr_buf) (void)nlr_buf +#endif + #if MICROPY_NLR_SETJMP #include "py/mpstate.h" NORETURN void nlr_setjmp_jump(void *val); // nlr_push() must be defined as a macro, because "The stack context will be // invalidated if the function which called setjmp() returns." -#define nlr_push(buf) ((buf)->prev = MP_STATE_THREAD(nlr_top), MP_STATE_THREAD(nlr_top) = (buf), setjmp((buf)->jmpbuf)) +#define nlr_push(buf) ( \ + (buf)->prev = MP_STATE_THREAD(nlr_top), \ + MP_NLR_SAVE_PYSTACK(buf), \ + MP_STATE_THREAD(nlr_top) = (buf), \ + setjmp((buf)->jmpbuf)) #define nlr_pop() { MP_STATE_THREAD(nlr_top) = MP_STATE_THREAD(nlr_top)->prev; } #define nlr_jump(val) nlr_setjmp_jump(val) #else diff --git a/py/nlrsetjmp.c b/py/nlrsetjmp.c index 1fb4594403..63376a5537 100644 --- a/py/nlrsetjmp.c +++ b/py/nlrsetjmp.c @@ -35,6 +35,7 @@ void nlr_setjmp_jump(void *val) { nlr_jump_fail(val); } top->ret_val = val; + MP_NLR_RESTORE_PYSTACK(top); *top_ptr = top->prev; longjmp(top->jmpbuf, 1); } diff --git a/py/nlrthumb.c b/py/nlrthumb.c index 6e7d717667..eab5759f21 100644 --- a/py/nlrthumb.c +++ b/py/nlrthumb.c @@ -82,6 +82,7 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); nlr->prev = *top; + MP_NLR_SAVE_PYSTACK(nlr); *top = nlr; return 0; // normal return } @@ -99,6 +100,7 @@ NORETURN __attribute__((naked)) void nlr_jump(void *val) { } top->ret_val = val; + MP_NLR_RESTORE_PYSTACK(top); *top_ptr = top->prev; __asm volatile ( diff --git a/py/nlrx64.c b/py/nlrx64.c index 847d10398e..ddcd761665 100644 --- a/py/nlrx64.c +++ b/py/nlrx64.c @@ -91,6 +91,7 @@ unsigned int nlr_push(nlr_buf_t *nlr) { __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); nlr->prev = *top; + MP_NLR_SAVE_PYSTACK(nlr); *top = nlr; return 0; // normal return } @@ -108,6 +109,7 @@ NORETURN void nlr_jump(void *val) { } top->ret_val = val; + MP_NLR_RESTORE_PYSTACK(top); *top_ptr = top->prev; __asm volatile ( diff --git a/py/nlrx86.c b/py/nlrx86.c index 094dea3cc8..3a27460eb6 100644 --- a/py/nlrx86.c +++ b/py/nlrx86.c @@ -73,6 +73,7 @@ unsigned int nlr_push(nlr_buf_t *nlr) { __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); nlr->prev = *top; + MP_NLR_SAVE_PYSTACK(nlr); *top = nlr; return 0; // normal return } @@ -90,6 +91,7 @@ NORETURN void nlr_jump(void *val) { } top->ret_val = val; + MP_NLR_RESTORE_PYSTACK(top); *top_ptr = top->prev; __asm volatile ( diff --git a/py/nlrxtensa.c b/py/nlrxtensa.c index 4520e7e7ac..5a969fc87c 100644 --- a/py/nlrxtensa.c +++ b/py/nlrxtensa.c @@ -58,6 +58,7 @@ unsigned int nlr_push(nlr_buf_t *nlr) { __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); nlr->prev = *top; + MP_NLR_SAVE_PYSTACK(nlr); *top = nlr; return 0; // normal return } @@ -75,6 +76,7 @@ NORETURN void nlr_jump(void *val) { } top->ret_val = val; + MP_NLR_RESTORE_PYSTACK(top); *top_ptr = top->prev; __asm volatile ( diff --git a/py/py.mk b/py/py.mk index f5faad1821..0b5d5f8c40 100644 --- a/py/py.mk +++ b/py/py.mk @@ -110,6 +110,7 @@ PY_O_BASENAME = \ nlrsetjmp.o \ malloc.o \ gc.o \ + pystack.o \ qstr.o \ vstr.o \ mpprint.o \ diff --git a/py/pystack.c b/py/pystack.c new file mode 100644 index 0000000000..767c307e9a --- /dev/null +++ b/py/pystack.c @@ -0,0 +1,56 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" + +#if MICROPY_ENABLE_PYSTACK + +void mp_pystack_init(void *start, void *end) { + MP_STATE_THREAD(pystack_start) = start; + MP_STATE_THREAD(pystack_end) = end; + MP_STATE_THREAD(pystack_cur) = start; +} + +void *mp_pystack_alloc(size_t n_bytes) { + n_bytes = (n_bytes + (MICROPY_PYSTACK_ALIGN - 1)) & ~(MICROPY_PYSTACK_ALIGN - 1); + #if MP_PYSTACK_DEBUG + n_bytes += MICROPY_PYSTACK_ALIGN; + #endif + if (MP_STATE_THREAD(pystack_cur) + n_bytes > MP_STATE_THREAD(pystack_end)) { + // out of memory in the pystack + mp_raise_recursion_depth(); + } + void *ptr = MP_STATE_THREAD(pystack_cur); + MP_STATE_THREAD(pystack_cur) += n_bytes; + #if MP_PYSTACK_DEBUG + *(size_t*)(MP_STATE_THREAD(pystack_cur) - MICROPY_PYSTACK_ALIGN) = n_bytes; + #endif + return ptr; +} + +#endif diff --git a/py/pystack.h b/py/pystack.h new file mode 100644 index 0000000000..82ac3743d1 --- /dev/null +++ b/py/pystack.h @@ -0,0 +1,123 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_PYSTACK_H +#define MICROPY_INCLUDED_PY_PYSTACK_H + +#include "py/mpstate.h" + +// Enable this debugging option to check that the amount of memory freed is +// consistent with amounts that were previously allocated. +#define MP_PYSTACK_DEBUG (0) + +#if MICROPY_ENABLE_PYSTACK + +void mp_pystack_init(void *start, void *end); +void *mp_pystack_alloc(size_t n_bytes); + +// This function can free multiple continuous blocks at once: just pass the +// pointer to the block that was allocated first and it and all subsequently +// allocated blocks will be freed. +static inline void mp_pystack_free(void *ptr) { + assert((uint8_t*)ptr >= MP_STATE_THREAD(pystack_start)); + assert((uint8_t*)ptr <= MP_STATE_THREAD(pystack_cur)); + #if MP_PYSTACK_DEBUG + size_t n_bytes_to_free = MP_STATE_THREAD(pystack_cur) - (uint8_t*)ptr; + size_t n_bytes = *(size_t*)(MP_STATE_THREAD(pystack_cur) - MICROPY_PYSTACK_ALIGN); + while (n_bytes < n_bytes_to_free) { + n_bytes += *(size_t*)(MP_STATE_THREAD(pystack_cur) - n_bytes - MICROPY_PYSTACK_ALIGN); + } + if (n_bytes != n_bytes_to_free) { + mp_printf(&mp_plat_print, "mp_pystack_free() failed: %u != %u\n", (uint)n_bytes_to_free, + (uint)*(size_t*)(MP_STATE_THREAD(pystack_cur) - MICROPY_PYSTACK_ALIGN)); + assert(0); + } + #endif + MP_STATE_THREAD(pystack_cur) = (uint8_t*)ptr; +} + +static inline void mp_pystack_realloc(void *ptr, size_t n_bytes) { + mp_pystack_free(ptr); + mp_pystack_alloc(n_bytes); +} + +static inline size_t mp_pystack_usage(void) { + return MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start); +} + +static inline size_t mp_pystack_limit(void) { + return MP_STATE_THREAD(pystack_end) - MP_STATE_THREAD(pystack_start); +} + +#endif + +#if !MICROPY_ENABLE_PYSTACK + +#define mp_local_alloc(n_bytes) alloca(n_bytes) + +static inline void mp_local_free(void *ptr) { + (void)ptr; +} + +static inline void *mp_nonlocal_alloc(size_t n_bytes) { + return m_new(uint8_t, n_bytes); +} + +static inline void *mp_nonlocal_realloc(void *ptr, size_t old_n_bytes, size_t new_n_bytes) { + return m_renew(uint8_t, ptr, old_n_bytes, new_n_bytes); +} + +static inline void mp_nonlocal_free(void *ptr, size_t n_bytes) { + m_del(uint8_t, ptr, n_bytes); +} + +#else + +static inline void *mp_local_alloc(size_t n_bytes) { + return mp_pystack_alloc(n_bytes); +} + +static inline void mp_local_free(void *ptr) { + mp_pystack_free(ptr); +} + +static inline void *mp_nonlocal_alloc(size_t n_bytes) { + return mp_pystack_alloc(n_bytes); +} + +static inline void *mp_nonlocal_realloc(void *ptr, size_t old_n_bytes, size_t new_n_bytes) { + (void)old_n_bytes; + mp_pystack_realloc(ptr, new_n_bytes); + return ptr; +} + +static inline void mp_nonlocal_free(void *ptr, size_t n_bytes) { + (void)n_bytes; + mp_pystack_free(ptr); +} + +#endif + +#endif // MICROPY_INCLUDED_PY_PYSTACK_H diff --git a/py/runtime.c b/py/runtime.c index 5fd053e1a2..3a4a8a93b0 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1457,7 +1457,7 @@ NORETURN void mp_raise_NotImplementedError(const char *msg) { mp_raise_msg(&mp_type_NotImplementedError, msg); } -#if MICROPY_STACK_CHECK +#if MICROPY_STACK_CHECK || MICROPY_ENABLE_PYSTACK NORETURN void mp_raise_recursion_depth(void) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError, MP_OBJ_NEW_QSTR(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded))); diff --git a/py/runtime.h b/py/runtime.h index a19f64c067..6288e88367 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -27,6 +27,7 @@ #define MICROPY_INCLUDED_PY_RUNTIME_H #include "py/mpstate.h" +#include "py/pystack.h" typedef enum { MP_VM_RETURN_NORMAL, From 1e5a33df413bbd8a8aa5bd880be445c684fc5506 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 26 Nov 2017 23:37:19 +1100 Subject: [PATCH 111/828] py: Convert all uses of alloca() to use new scoped allocation API. --- py/builtinimport.c | 5 +++-- py/compile.c | 3 ++- py/objboundmeth.c | 8 ++++++++ py/objfun.c | 12 ++++++++++++ py/runtime.c | 3 ++- py/vm.c | 16 ++++++++++++++-- 6 files changed, 41 insertions(+), 6 deletions(-) diff --git a/py/builtinimport.c b/py/builtinimport.c index 9235e946c6..2157902c95 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -318,7 +318,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { } uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len); - char *new_mod = alloca(new_mod_l); + char *new_mod = mp_local_alloc(new_mod_l); memcpy(new_mod, this_name, p - this_name); if (mod_len != 0) { new_mod[p - this_name] = '.'; @@ -326,9 +326,10 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { } qstr new_mod_q = qstr_from_strn(new_mod, new_mod_l); + mp_local_free(new_mod); DEBUG_printf("Resolved base name for relative import: '%s'\n", qstr_str(new_mod_q)); module_name = MP_OBJ_NEW_QSTR(new_mod_q); - mod_str = new_mod; + mod_str = qstr_str(new_mod_q); mod_len = new_mod_l; } diff --git a/py/compile.c b/py/compile.c index ee017498ac..52d10ee5e8 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1050,7 +1050,7 @@ STATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) { for (int i = 0; i < n; i++) { len += qstr_len(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i])); } - char *q_ptr = alloca(len); + char *q_ptr = mp_local_alloc(len); char *str_dest = q_ptr; for (int i = 0; i < n; i++) { if (i > 0) { @@ -1062,6 +1062,7 @@ STATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) { str_dest += str_src_len; } qstr q_full = qstr_from_strn(q_ptr, len); + mp_local_free(q_ptr); EMIT_ARG(import_name, q_full); if (is_as) { for (int i = 1; i < n; i++) { diff --git a/py/objboundmeth.c b/py/objboundmeth.c index 890f8b15b6..b0df6a68a7 100644 --- a/py/objboundmeth.c +++ b/py/objboundmeth.c @@ -51,6 +51,9 @@ mp_obj_t mp_call_method_self_n_kw(mp_obj_t meth, mp_obj_t self, size_t n_args, s // need to insert self before all other args and then call meth size_t n_total = n_args + 2 * n_kw; mp_obj_t *args2 = NULL; + #if MICROPY_ENABLE_PYSTACK + args2 = mp_pystack_alloc(sizeof(mp_obj_t) * (1 + n_total)); + #else mp_obj_t *free_args2 = NULL; if (n_total > 4) { // try to use heap to allocate temporary args array @@ -61,12 +64,17 @@ mp_obj_t mp_call_method_self_n_kw(mp_obj_t meth, mp_obj_t self, size_t n_args, s // (fallback to) use stack to allocate temporary args array args2 = alloca(sizeof(mp_obj_t) * (1 + n_total)); } + #endif args2[0] = self; memcpy(args2 + 1, args, n_total * sizeof(mp_obj_t)); mp_obj_t res = mp_call_function_n_kw(meth, n_args + 1, n_kw, args2); + #if MICROPY_ENABLE_PYSTACK + mp_pystack_free(args2); + #else if (free_args2 != NULL) { m_del(mp_obj_t, free_args2, 1 + n_total); } + #endif return res; } diff --git a/py/objfun.c b/py/objfun.c index 8fb3ec6fa2..e6d33d287c 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -225,6 +225,9 @@ mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args DECODE_CODESTATE_SIZE(self->bytecode, n_state, state_size); mp_code_state_t *code_state; + #if MICROPY_ENABLE_PYSTACK + code_state = mp_pystack_alloc(sizeof(mp_code_state_t) + state_size); + #else // If we use m_new_obj_var(), then on no memory, MemoryError will be // raised. But this is not correct exception for a function call, // RuntimeError should be raised instead. So, we use m_new_obj_var_maybe(), @@ -234,6 +237,7 @@ mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args if (!code_state) { return NULL; } + #endif INIT_CODESTATE(code_state, self, n_args, n_kw, args); @@ -260,6 +264,9 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const // allocate state for locals and stack mp_code_state_t *code_state = NULL; + #if MICROPY_ENABLE_PYSTACK + code_state = mp_pystack_alloc(sizeof(mp_code_state_t) + state_size); + #else if (state_size > VM_MAX_STATE_ON_STACK) { code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size); } @@ -267,6 +274,7 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const code_state = alloca(sizeof(mp_code_state_t) + state_size); state_size = 0; // indicate that we allocated using alloca } + #endif INIT_CODESTATE(code_state, self, n_args, n_kw, args); @@ -312,10 +320,14 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const result = code_state->state[n_state - 1]; } + #if MICROPY_ENABLE_PYSTACK + mp_pystack_free(code_state); + #else // free the state if it was allocated on the heap if (state_size != 0) { m_del_var(mp_code_state_t, byte, state_size, code_state); } + #endif if (vm_return_kind == MP_VM_RETURN_NORMAL) { return result; diff --git a/py/runtime.c b/py/runtime.c index 3a4a8a93b0..8df0c0a080 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1348,11 +1348,12 @@ import_error: const char *pkg_name = mp_obj_str_get_data(dest[0], &pkg_name_len); const uint dot_name_len = pkg_name_len + 1 + qstr_len(name); - char *dot_name = alloca(dot_name_len); + char *dot_name = mp_local_alloc(dot_name_len); memcpy(dot_name, pkg_name, pkg_name_len); dot_name[pkg_name_len] = '.'; memcpy(dot_name + pkg_name_len + 1, qstr_str(name), qstr_len(name)); qstr dot_name_q = qstr_from_strn(dot_name, dot_name_len); + mp_local_free(dot_name); mp_obj_t args[5]; args[0] = MP_OBJ_NEW_QSTR(dot_name_q); diff --git a/py/vm.c b/py/vm.c index 5011af5c3e..a8a73f3239 100644 --- a/py/vm.c +++ b/py/vm.c @@ -1108,7 +1108,13 @@ unwind_return: if (code_state->prev != NULL) { mp_obj_t res = *sp; mp_globals_set(code_state->old_globals); - code_state = code_state->prev; + mp_code_state_t *new_code_state = code_state->prev; + #if MICROPY_ENABLE_PYSTACK + // The sizeof in the following statement does not include the size of the variable + // part of the struct. This arg is anyway not used if pystack is enabled. + mp_nonlocal_free(code_state, sizeof(mp_code_state_t)); + #endif + code_state = new_code_state; *code_state->sp = res; goto run_code_state; } @@ -1450,7 +1456,13 @@ unwind_loop: #if MICROPY_STACKLESS } else if (code_state->prev != NULL) { mp_globals_set(code_state->old_globals); - code_state = code_state->prev; + mp_code_state_t *new_code_state = code_state->prev; + #if MICROPY_ENABLE_PYSTACK + // The sizeof in the following statement does not include the size of the variable + // part of the struct. This arg is anyway not used if pystack is enabled. + mp_nonlocal_free(code_state, sizeof(mp_code_state_t)); + #endif + code_state = new_code_state; size_t n_state = mp_decode_uint_value(code_state->fun_bc->bytecode); fastn = &code_state->state[n_state - 1]; exc_stack = (mp_exc_stack_t*)(code_state->state + n_state); From 6df7b2f2fee71e231927511d4baf58ff86eb7983 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 26 Nov 2017 23:38:50 +1100 Subject: [PATCH 112/828] extmod/machine_signal: Change VLA to use new scoped allocation API. --- extmod/machine_signal.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/extmod/machine_signal.c b/extmod/machine_signal.c index 78d0c3feef..3f9f5af947 100644 --- a/extmod/machine_signal.c +++ b/extmod/machine_signal.c @@ -58,7 +58,7 @@ STATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t // If first argument isn't a Pin-like object, we filter out "invert" // from keyword arguments and pass them all to the exported Pin // constructor to create one. - mp_obj_t pin_args[n_args + n_kw * 2]; + mp_obj_t *pin_args = mp_local_alloc((n_args + n_kw * 2) * sizeof(mp_obj_t)); memcpy(pin_args, args, n_args * sizeof(mp_obj_t)); const mp_obj_t *src = args + n_args; mp_obj_t *dst = pin_args + n_args; @@ -88,6 +88,8 @@ STATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t // will just ignore it as set a concrete type. If not, we'd need // to expose port's "default" pin type too. pin = MICROPY_PY_MACHINE_PIN_MAKE_NEW(NULL, n_args, n_kw, pin_args); + + mp_local_free(pin_args); } else #endif From ab750ee2fb6329eb7b0b06ff44a0d0d152ba32b7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 26 Nov 2017 23:39:25 +1100 Subject: [PATCH 113/828] extmod/modure: Convert alloca() to use new scoped allocation API. --- extmod/modure.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extmod/modure.c b/extmod/modure.c index 78de4706d2..d0180881d3 100644 --- a/extmod/modure.c +++ b/extmod/modure.c @@ -144,7 +144,7 @@ STATIC mp_obj_t re_split(size_t n_args, const mp_obj_t *args) { } mp_obj_t retval = mp_obj_new_list(0, NULL); - const char **caps = alloca(caps_num * sizeof(char*)); + const char **caps = mp_local_alloc(caps_num * sizeof(char*)); while (true) { // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char memset((char**)caps, 0, caps_num * sizeof(char*)); @@ -165,6 +165,7 @@ STATIC mp_obj_t re_split(size_t n_args, const mp_obj_t *args) { break; } } + mp_local_free(caps); mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte*)subj.begin, subj.end - subj.begin); mp_obj_list_append(retval, s); From 357486d9b455a8ac0c7066a997ebd4ee8e22b38f Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 26 Nov 2017 23:40:30 +1100 Subject: [PATCH 114/828] unix: Add support for using the Python stack. --- ports/unix/main.c | 5 +++++ ports/unix/mpthreadport.c | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/ports/unix/main.c b/ports/unix/main.c index 25f3e04fb8..03f2f357ee 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -440,6 +440,11 @@ MP_NOINLINE int main_(int argc, char **argv) { gc_init(heap, heap + heap_size); #endif + #if MICROPY_ENABLE_PYSTACK + static mp_obj_t pystack[1024]; + mp_pystack_init(pystack, &pystack[MP_ARRAY_SIZE(pystack)]); + #endif + mp_init(); char *home = getenv("HOME"); diff --git a/ports/unix/mpthreadport.c b/ports/unix/mpthreadport.c index 8c636a4457..baca0a2b1e 100644 --- a/ports/unix/mpthreadport.c +++ b/ports/unix/mpthreadport.c @@ -66,6 +66,10 @@ STATIC void mp_thread_gc(int signo, siginfo_t *info, void *context) { // that we don't need the extra information, enough is captured by the // gc_collect_regs_and_stack function above //gc_collect_root((void**)context, sizeof(ucontext_t) / sizeof(uintptr_t)); + #if MICROPY_ENABLE_PYSTACK + void **ptrs = (void**)(void*)MP_STATE_THREAD(pystack_start); + gc_collect_root(ptrs, (MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start)) / sizeof(void*)); + #endif thread_signal_done = 1; } } From 971699abe7c9ac07c3059cbbc452043e35eb6200 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 26 Nov 2017 23:40:42 +1100 Subject: [PATCH 115/828] stm32: Add support for using the Python stack. --- ports/stm32/main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 16279d073d..9a83f9f363 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -511,6 +511,11 @@ soft_reset: // GC init gc_init(&_heap_start, &_heap_end); + #if MICROPY_ENABLE_PYSTACK + static mp_obj_t pystack[384]; + mp_pystack_init(pystack, &pystack[384]); + #endif + // MicroPython init mp_init(); mp_obj_list_init(mp_sys_path, 0); From 30fd8484ebe41faad467fbc8dd4a6f72250f203c Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 26 Nov 2017 23:48:23 +1100 Subject: [PATCH 116/828] py/runtime: Use the Python stack when building *arg and **kwarg state. With MICROPY_ENABLE_PYSTACK enabled the following language constructs no longer allocate on the heap: f(*arg), f(**kwarg). --- py/runtime.c | 12 ++++++------ py/vm.c | 16 ++++++++++++++-- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/py/runtime.c b/py/runtime.c index 8df0c0a080..41f2f6976e 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -669,7 +669,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ // allocate memory for the new array of args args2_alloc = 1 + n_args + 2 * (n_kw + kw_dict_len); - args2 = m_new(mp_obj_t, args2_alloc); + args2 = mp_nonlocal_alloc(args2_alloc * sizeof(mp_obj_t)); // copy the self if (self != MP_OBJ_NULL) { @@ -690,7 +690,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ // allocate memory for the new array of args args2_alloc = 1 + n_args + len + 2 * (n_kw + kw_dict_len); - args2 = m_new(mp_obj_t, args2_alloc); + args2 = mp_nonlocal_alloc(args2_alloc * sizeof(mp_obj_t)); // copy the self if (self != MP_OBJ_NULL) { @@ -706,7 +706,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ // allocate memory for the new array of args args2_alloc = 1 + n_args + 2 * (n_kw + kw_dict_len) + 3; - args2 = m_new(mp_obj_t, args2_alloc); + args2 = mp_nonlocal_alloc(args2_alloc * sizeof(mp_obj_t)); // copy the self if (self != MP_OBJ_NULL) { @@ -723,7 +723,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ mp_obj_t item; while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { if (args2_len >= args2_alloc) { - args2 = m_renew(mp_obj_t, args2, args2_alloc, args2_alloc * 2); + args2 = mp_nonlocal_realloc(args2, args2_alloc * sizeof(mp_obj_t), args2_alloc * 2 * sizeof(mp_obj_t)); args2_alloc *= 2; } args2[args2_len++] = item; @@ -774,7 +774,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ if (new_alloc < 4) { new_alloc = 4; } - args2 = m_renew(mp_obj_t, args2, args2_alloc, new_alloc); + args2 = mp_nonlocal_realloc(args2, args2_alloc * sizeof(mp_obj_t), new_alloc * sizeof(mp_obj_t)); args2_alloc = new_alloc; } @@ -806,7 +806,7 @@ mp_obj_t mp_call_method_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ob mp_call_prepare_args_n_kw_var(have_self, n_args_n_kw, args, &out_args); mp_obj_t res = mp_call_function_n_kw(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args); - m_del(mp_obj_t, out_args.args, out_args.n_alloc); + mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t)); return res; } diff --git a/py/vm.c b/py/vm.c index a8a73f3239..b18a2b5e32 100644 --- a/py/vm.c +++ b/py/vm.c @@ -966,7 +966,11 @@ unwind_jump:; mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args); - m_del(mp_obj_t, out_args.args, out_args.n_alloc); + #if !MICROPY_ENABLE_PYSTACK + // Freeing args at this point does not follow a LIFO order so only do it if + // pystack is not enabled. For pystack, they are freed when code_state is. + mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t)); + #endif if (new_state) { new_state->prev = code_state; code_state = new_state; @@ -1043,7 +1047,11 @@ unwind_jump:; mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args); - m_del(mp_obj_t, out_args.args, out_args.n_alloc); + #if !MICROPY_ENABLE_PYSTACK + // Freeing args at this point does not follow a LIFO order so only do it if + // pystack is not enabled. For pystack, they are freed when code_state is. + mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t)); + #endif if (new_state) { new_state->prev = code_state; code_state = new_state; @@ -1110,6 +1118,8 @@ unwind_return: mp_globals_set(code_state->old_globals); mp_code_state_t *new_code_state = code_state->prev; #if MICROPY_ENABLE_PYSTACK + // Free code_state, and args allocated by mp_call_prepare_args_n_kw_var + // (The latter is implicitly freed when using pystack due to its LIFO nature.) // The sizeof in the following statement does not include the size of the variable // part of the struct. This arg is anyway not used if pystack is enabled. mp_nonlocal_free(code_state, sizeof(mp_code_state_t)); @@ -1458,6 +1468,8 @@ unwind_loop: mp_globals_set(code_state->old_globals); mp_code_state_t *new_code_state = code_state->prev; #if MICROPY_ENABLE_PYSTACK + // Free code_state, and args allocated by mp_call_prepare_args_n_kw_var + // (The latter is implicitly freed when using pystack due to its LIFO nature.) // The sizeof in the following statement does not include the size of the variable // part of the struct. This arg is anyway not used if pystack is enabled. mp_nonlocal_free(code_state, sizeof(mp_code_state_t)); From e02cb9ec318580497dbb17f369a61d9e932094e5 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 11 Dec 2017 11:56:20 +0200 Subject: [PATCH 117/828] tests/heapalloc_*: Refactor some tests to work in strict stackless mode. In strict stackless mode, it's not possible to make a function call with heap locked (because function activation record aka frame is allocated on heap). So, if the only purpose of function is to introduce local variable scope, move heap lock/unlock calls inside the function. --- tests/micropython/heapalloc_exc_raise.py | 4 ++-- tests/micropython/heapalloc_iter.py | 4 ++-- tests/micropython/heapalloc_traceback.py | 4 ++-- tests/micropython/heapalloc_traceback.py.exp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/micropython/heapalloc_exc_raise.py b/tests/micropython/heapalloc_exc_raise.py index d60e14ce5d..fb63a84bf3 100644 --- a/tests/micropython/heapalloc_exc_raise.py +++ b/tests/micropython/heapalloc_exc_raise.py @@ -5,6 +5,7 @@ import micropython e = ValueError("error") def func(): + micropython.heap_lock() try: # This works as is because traceback is not allocated # if not possible (heap is locked, no memory). If heap @@ -16,8 +17,7 @@ def func(): raise e except Exception as e2: print(e2) + micropython.heap_unlock() -micropython.heap_lock() func() print("ok") -micropython.heap_unlock() diff --git a/tests/micropython/heapalloc_iter.py b/tests/micropython/heapalloc_iter.py index 79461f999a..30ac82e14b 100644 --- a/tests/micropython/heapalloc_iter.py +++ b/tests/micropython/heapalloc_iter.py @@ -11,8 +11,10 @@ except (ImportError, AttributeError): heap_lock = heap_unlock = lambda:0 def do_iter(l): + heap_lock() for i in l: print(i) + heap_unlock() def gen_func(): yield 1 @@ -55,7 +57,6 @@ print(sum(t)) heap_unlock() # test iterating over collections with the heap locked -heap_lock() do_iter(b'123') do_iter(ba) do_iter(ar) @@ -66,4 +67,3 @@ do_iter(s) do_iter(fs) do_iter(g1) do_iter(g2) -heap_unlock() diff --git a/tests/micropython/heapalloc_traceback.py b/tests/micropython/heapalloc_traceback.py index f4212b6ce1..813dea4b21 100644 --- a/tests/micropython/heapalloc_traceback.py +++ b/tests/micropython/heapalloc_traceback.py @@ -16,17 +16,17 @@ except: pass def test(): + micropython.heap_lock() global global_exc global_exc.__traceback__ = None try: raise global_exc except StopIteration: print('StopIteration') + micropython.heap_unlock() # call test() with heap allocation disabled -micropython.heap_lock() test() -micropython.heap_unlock() # print the exception that was raised buf = uio.StringIO() diff --git a/tests/micropython/heapalloc_traceback.py.exp b/tests/micropython/heapalloc_traceback.py.exp index 291bbd697c..facd0af137 100644 --- a/tests/micropython/heapalloc_traceback.py.exp +++ b/tests/micropython/heapalloc_traceback.py.exp @@ -1,5 +1,5 @@ StopIteration Traceback (most recent call last): - File , line 22, in test + File , line 23, in test StopIteration: From 016f83053669ee56561bebd8e9b65dac77b670ac Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 11 Dec 2017 11:58:44 +0200 Subject: [PATCH 118/828] tests/heapalloc, heapalloc_super: Skip in strict stackless mode. These tests involves testing allocation-free function calling, and in strict stackless mode, it's not possible to make a function call with heap locked (because function activation record aka frame is allocated on the heap). --- tests/micropython/heapalloc.py | 9 +++++++++ tests/micropython/heapalloc_super.py | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/tests/micropython/heapalloc.py b/tests/micropython/heapalloc.py index 62f26df6af..f74bb92c85 100644 --- a/tests/micropython/heapalloc.py +++ b/tests/micropython/heapalloc.py @@ -2,6 +2,15 @@ import micropython +# Check for stackless build, which can't call functions without +# allocating a frame on heap. +try: + def stackless(): pass + micropython.heap_lock(); stackless(); micropython.heap_unlock() +except RuntimeError: + print("SKIP") + raise SystemExit + def f1(a): print(a) diff --git a/tests/micropython/heapalloc_super.py b/tests/micropython/heapalloc_super.py index 1cf5293d2d..a8c23393e4 100644 --- a/tests/micropython/heapalloc_super.py +++ b/tests/micropython/heapalloc_super.py @@ -1,6 +1,15 @@ # test super() operations which don't require allocation import micropython +# Check for stackless build, which can't call functions without +# allocating a frame on heap. +try: + def stackless(): pass + micropython.heap_lock(); stackless(); micropython.heap_unlock() +except RuntimeError: + print("SKIP") + raise SystemExit + class A: def foo(self): print('A foo') From 9c027073568d9be43bd1aabcac60a6ff208c4299 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 11 Dec 2017 22:38:30 +1100 Subject: [PATCH 119/828] py/objexcept: Use INT_FMT when printing errno value. --- py/objexcept.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/objexcept.c b/py/objexcept.c index b87609a6b2..380bc3534e 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -118,7 +118,7 @@ STATIC void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_pr if (o->base.type == &mp_type_OSError && MP_OBJ_IS_SMALL_INT(o->args->items[0])) { qstr qst = mp_errno_to_str(o->args->items[0]); if (qst != MP_QSTR_NULL) { - mp_printf(print, "[Errno %d] %q", MP_OBJ_SMALL_INT_VALUE(o->args->items[0]), qst); + mp_printf(print, "[Errno " INT_FMT "] %q", MP_OBJ_SMALL_INT_VALUE(o->args->items[0]), qst); return; } } From 2759bec8587b0c0b7da1fa3a013e4f1b1530ad27 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 11 Dec 2017 22:39:12 +1100 Subject: [PATCH 120/828] py: Extend nan-boxing config to have 47-bit small integers. The nan-boxing representation has an extra 16-bits of space to store small-int values, and making use of it allows to create and manipulate full 32-bit positive integers (ie up to 0xffffffff) without using the heap. --- py/mpconfig.h | 2 +- py/obj.h | 4 ++-- py/parse.c | 18 +++++++++++++++--- py/smallint.h | 6 +++--- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/py/mpconfig.h b/py/mpconfig.h index 96cd8c651a..19bae4f88a 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -79,7 +79,7 @@ // - seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff 64-bit fp, e != 0x7ff // - s1111111 11110000 00000000 00000000 00000000 00000000 00000000 00000000 +/- inf // - 01111111 11111000 00000000 00000000 00000000 00000000 00000000 00000000 normalised nan -// - 01111111 11111101 00000000 00000000 iiiiiiii iiiiiiii iiiiiiii iiiiiii1 small int +// - 01111111 11111101 iiiiiiii iiiiiiii iiiiiiii iiiiiiii iiiiiiii iiiiiii1 small int // - 01111111 11111110 00000000 00000000 qqqqqqqq qqqqqqqq qqqqqqqq qqqqqqq1 str // - 01111111 11111100 00000000 00000000 pppppppp pppppppp pppppppp pppppp00 ptr (4 byte alignment) // Stored as O = R + 0x8004000000000000, retrieved as R = O - 0x8004000000000000. diff --git a/py/obj.h b/py/obj.h index 31c3ce95c8..10cb48961f 100644 --- a/py/obj.h +++ b/py/obj.h @@ -170,8 +170,8 @@ static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 0xffff000000000000) == 0x0001000000000000); } -#define MP_OBJ_SMALL_INT_VALUE(o) (((intptr_t)(o)) >> 1) -#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)(((uintptr_t)(small_int)) << 1) | 0x0001000000000001) +#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)((o) << 16)) >> 17) +#define MP_OBJ_NEW_SMALL_INT(small_int) (((((uint64_t)(small_int)) & 0x7fffffffffff) << 1) | 0x0001000000000001) static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 0xffff000000000000) == 0x0002000000000000); } diff --git a/py/parse.c b/py/parse.c index f7fe30418c..b80cc8fb1a 100644 --- a/py/parse.c +++ b/py/parse.c @@ -369,6 +369,18 @@ STATIC mp_parse_node_t make_node_const_object(parser_t *parser, size_t src_line, return (mp_parse_node_t)pn; } +STATIC mp_parse_node_t mp_parse_node_new_small_int_checked(parser_t *parser, mp_obj_t o_val) { + (void)parser; + mp_int_t val = MP_OBJ_SMALL_INT_VALUE(o_val); + #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D + // A parse node is only 32-bits and the small-int value must fit in 31-bits + if (((val ^ (val << 1)) & 0xffffffff80000000) != 0) { + return make_node_const_object(parser, 0, o_val); + } + #endif + return mp_parse_node_new_small_int(val); +} + STATIC void push_result_token(parser_t *parser, const rule_t *rule) { mp_parse_node_t pn; mp_lexer_t *lex = parser->lexer; @@ -380,7 +392,7 @@ STATIC void push_result_token(parser_t *parser, const rule_t *rule) { if (rule->rule_id == RULE_atom && (elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP)) != NULL) { if (MP_OBJ_IS_SMALL_INT(elem->value)) { - pn = mp_parse_node_new_small_int(MP_OBJ_SMALL_INT_VALUE(elem->value)); + pn = mp_parse_node_new_small_int_checked(parser, elem->value); } else { pn = make_node_const_object(parser, lex->tok_line, elem->value); } @@ -394,7 +406,7 @@ STATIC void push_result_token(parser_t *parser, const rule_t *rule) { } else if (lex->tok_kind == MP_TOKEN_INTEGER) { mp_obj_t o = mp_parse_num_integer(lex->vstr.buf, lex->vstr.len, 0, lex); if (MP_OBJ_IS_SMALL_INT(o)) { - pn = mp_parse_node_new_small_int(MP_OBJ_SMALL_INT_VALUE(o)); + pn = mp_parse_node_new_small_int_checked(parser, o); } else { pn = make_node_const_object(parser, lex->tok_line, o); } @@ -686,7 +698,7 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args pop_result(parser); } if (MP_OBJ_IS_SMALL_INT(arg0)) { - push_result_node(parser, mp_parse_node_new_small_int(MP_OBJ_SMALL_INT_VALUE(arg0))); + push_result_node(parser, mp_parse_node_new_small_int_checked(parser, arg0)); } else { // TODO reuse memory for parse node struct? push_result_node(parser, make_node_const_object(parser, 0, arg0)); diff --git a/py/smallint.h b/py/smallint.h index 42679a78fb..6a3c75236c 100644 --- a/py/smallint.h +++ b/py/smallint.h @@ -50,10 +50,10 @@ #elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D -#define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)0xffffffff80000000) >> 1)) -#define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & 0xffffffff80000000) == 0) +#define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)0xffff800000000000) >> 1)) +#define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & 0xffff800000000000) == 0) // Mask to truncate mp_int_t to positive value -#define MP_SMALL_INT_POSITIVE_MASK ~(0xffffffff80000000 | (0xffffffff80000000 >> 1)) +#define MP_SMALL_INT_POSITIVE_MASK ~(0xffff800000000000 | (0xffff800000000000 >> 1)) #endif From d3f82bc42576ccd80206a17a4941fd5c28c56530 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 11 Dec 2017 22:51:52 +1100 Subject: [PATCH 121/828] py/mpstate.h: Remove obsolete comment about nlr_top being coded in asm. --- py/mpstate.h | 1 - 1 file changed, 1 deletion(-) diff --git a/py/mpstate.h b/py/mpstate.h index d3b53f9151..45e89590f7 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -215,7 +215,6 @@ typedef struct _mp_state_thread_t { mp_obj_dict_t *dict_locals; mp_obj_dict_t *dict_globals; - // Note: nlr asm code has the offset of this hard-coded nlr_buf_t *nlr_top; // ROOT POINTER // Stack top at the start of program From d32d22dfd79439e07739166eaa3f7e41466c7ec8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 30 Nov 2017 10:31:42 +1100 Subject: [PATCH 122/828] py/objtype: Implement better support for overriding native's __init__. This patch cleans up and generalises part of the code which handles overriding and calling a native base-class's __init__ method. It defers the call to the native make_new() function until after the user (Python) __init__() method has run. That user method now has the chance to call the native __init__/make_new and pass it different arguments. If the user doesn't call the super().__init__ method then it will be called automatically after the user code finishes, to finalise construction of the instance. --- py/objexcept.c | 15 ---------- py/objtype.c | 78 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 64 insertions(+), 29 deletions(-) diff --git a/py/objexcept.c b/py/objexcept.c index 380bc3534e..524f105ce1 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -212,27 +212,12 @@ STATIC void exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { } } -STATIC mp_obj_t exc___init__(size_t n_args, const mp_obj_t *args) { - mp_obj_exception_t *self = MP_OBJ_TO_PTR(args[0]); - mp_obj_t argst = mp_obj_new_tuple(n_args - 1, args + 1); - self->args = MP_OBJ_TO_PTR(argst); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(exc___init___obj, 1, MP_OBJ_FUN_ARGS_MAX, exc___init__); - -STATIC const mp_rom_map_elem_t exc_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&exc___init___obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(exc_locals_dict, exc_locals_dict_table); - const mp_obj_type_t mp_type_BaseException = { { &mp_type_type }, .name = MP_QSTR_BaseException, .print = mp_obj_exception_print, .make_new = mp_obj_exception_make_new, .attr = exception_attr, - .locals_dict = (mp_obj_dict_t*)&exc_locals_dict, }; #define MP_DEFINE_EXCEPTION(exc_name, base_name) \ diff --git a/py/objtype.c b/py/objtype.c index 267cae8156..22c8f01bcb 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -46,14 +46,6 @@ STATIC mp_obj_t static_class_method_make_new(const mp_obj_type_t *self_in, size_ /******************************************************************************/ // instance object -STATIC mp_obj_t mp_obj_new_instance(const mp_obj_type_t *class, size_t subobjs) { - mp_obj_instance_t *o = m_new_obj_var(mp_obj_instance_t, mp_obj_t, subobjs); - o->base.type = class; - mp_map_init(&o->members, 0); - mp_seq_clear(o->subobj, 0, subobjs, sizeof(*o->subobj)); - return MP_OBJ_FROM_PTR(o); -} - STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_type_t **last_native_base) { int count = 0; for (;;) { @@ -87,6 +79,30 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t } } +// This wrapper function is allows a subclass of a native type to call the +// __init__() method (corresponding to type->make_new) of the native type. +STATIC mp_obj_t native_base_init_wrapper(size_t n_args, const mp_obj_t *args) { + mp_obj_instance_t *self = MP_OBJ_TO_PTR(args[0]); + const mp_obj_type_t *native_base = NULL; + instance_count_native_bases(self->base.type, &native_base); + self->subobj[0] = native_base->make_new(native_base, n_args - 1, 0, args + 1); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(native_base_init_wrapper_obj, 1, MP_OBJ_FUN_ARGS_MAX, native_base_init_wrapper); + +STATIC mp_obj_t mp_obj_new_instance(const mp_obj_type_t *class, size_t subobjs) { + mp_obj_instance_t *o = m_new_obj_var(mp_obj_instance_t, mp_obj_t, subobjs); + o->base.type = class; + mp_map_init(&o->members, 0); + // Initialise the native base-class slot (should be 1 at most) with a valid + // object. It doesn't matter which object, so long as it can be uniquely + // distinguished from a native class that is initialised. + if (subobjs != 0) { + o->subobj[0] = MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj); + } + return MP_OBJ_FROM_PTR(o); +} + // TODO // This implements depth-first left-to-right MRO, which is not compliant with Python3 MRO // http://python-history.blogspot.com/2010/06/method-resolution-order.html @@ -280,7 +296,13 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size if (init_fn[0] == MP_OBJ_SENTINEL) { // Native type's constructor is what wins - it gets all our arguments, // and none Python classes are initialized at all. - o->subobj[0] = native_base->make_new(native_base, n_args, n_kw, args); + + // Since type->make_new() implements both __new__() and __init__() in + // one go, of which the latter may be overridden by the Python subclass, + // we defer (see the end of this function) the call of the native + // constructor to give a chance for the Python __init__() method to call + // said native constructor. + } else if (init_fn[0] != MP_OBJ_NULL) { // now call Python class __new__ function with all args if (n_args == 0 && n_kw == 0) { @@ -305,6 +327,8 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size o = MP_OBJ_TO_PTR(new_ret); // now call Python class __init__ function with all args + // This method has a chance to call super().__init__() to construct a + // possible native base class. init_fn[0] = init_fn[1] = MP_OBJ_NULL; lookup.obj = o; lookup.attr = MP_QSTR___init__; @@ -333,6 +357,12 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size } + // If the type had a native base that was not explicitly initialised + // (constructed) by the Python __init__() method then construct it now. + if (native_base != NULL && o->subobj[0] == MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj)) { + o->subobj[0] = native_base->make_new(native_base, n_args, n_kw, args); + } + return MP_OBJ_FROM_PTR(o); } @@ -1107,6 +1137,11 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { .is_type = false, }; + // Allow a call super().__init__() to reach any native base classes + if (attr == MP_QSTR___init__) { + lookup.meth_offset = offsetof(mp_obj_type_t, make_new); + } + if (type->parent == NULL) { // no parents, do nothing #if MICROPY_MULTIPLE_INHERITANCE @@ -1116,19 +1151,34 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { const mp_obj_t *items = parent_tuple->items; for (size_t i = 0; i < len; i++) { assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type)); + if (MP_OBJ_TO_PTR(items[i]) == &mp_type_object) { + // The "object" type will be searched at the end of this function, + // and we don't want to lookup native methods in object. + continue; + } mp_obj_class_lookup(&lookup, (mp_obj_type_t*)MP_OBJ_TO_PTR(items[i])); if (dest[0] != MP_OBJ_NULL) { - return; + break; } } #endif - } else { + } else if (type->parent != &mp_type_object) { mp_obj_class_lookup(&lookup, type->parent); - if (dest[0] != MP_OBJ_NULL) { - return; - } } + if (dest[0] != MP_OBJ_NULL) { + if (dest[0] == MP_OBJ_SENTINEL) { + // Looked up native __init__ so defer to it + dest[0] = MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj); + dest[1] = self->obj; + } + return; + } + + // Reset meth_offset so we don't look up any native methods in object, + // because object never takes up the native base-class slot. + lookup.meth_offset = 0; + mp_obj_class_lookup(&lookup, &mp_type_object); } From fd0b0db8738efcee4b0b4d5c337aa2ad9c1ae3b0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 30 Nov 2017 10:32:35 +1100 Subject: [PATCH 123/828] tests/basics: Add test for overriding a native base-class's init method. --- tests/basics/subclass_native_init.py | 44 ++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 tests/basics/subclass_native_init.py diff --git a/tests/basics/subclass_native_init.py b/tests/basics/subclass_native_init.py new file mode 100644 index 0000000000..38d2f23ac3 --- /dev/null +++ b/tests/basics/subclass_native_init.py @@ -0,0 +1,44 @@ +# test subclassing a native type and overriding __init__ + +# overriding list.__init__() +class L(list): + def __init__(self, a, b): + super().__init__([a, b]) +print(L(2, 3)) + +# inherits implicitly from object +class A: + def __init__(self): + print("A.__init__") + super().__init__() +A() + +# inherits explicitly from object +class B(object): + def __init__(self): + print("B.__init__") + super().__init__() +B() + +# multiple inheritance with object explicitly mentioned +class C: + pass +class D(C, object): + def __init__(self): + print('D.__init__') + super().__init__() + def reinit(self): + print('D.foo') + super().__init__() +a = D() +a.__init__() +a.reinit() + +# call __init__() after object is already init'd +class L(list): + def reinit(self): + super().__init__(range(2)) +a = L(range(5)) +print(a) +a.reinit() +print(a) From 3c28df16586157b6b80e7437559c36f05a309e24 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 12 Dec 2017 14:00:16 +1100 Subject: [PATCH 124/828] tests/extmod: Add test which subclasses framebuf.FrameBuffer. --- tests/extmod/framebuf_subclass.py | 20 ++++++++++++++++++++ tests/extmod/framebuf_subclass.py.exp | 1 + 2 files changed, 21 insertions(+) create mode 100644 tests/extmod/framebuf_subclass.py create mode 100644 tests/extmod/framebuf_subclass.py.exp diff --git a/tests/extmod/framebuf_subclass.py b/tests/extmod/framebuf_subclass.py new file mode 100644 index 0000000000..6363c224fb --- /dev/null +++ b/tests/extmod/framebuf_subclass.py @@ -0,0 +1,20 @@ +# test subclassing framebuf.FrameBuffer + +try: + import framebuf +except ImportError: + print('SKIP') + raise SystemExit + +class FB(framebuf.FrameBuffer): + def __init__(self, n): + self.n = n + super().__init__(bytearray(2 * n * n), n, n, framebuf.RGB565) + + def foo(self): + self.hline(0, 2, self.n, 0x0304) + +fb = FB(n=3) +fb.pixel(0, 0, 0x0102) +fb.foo() +print(bytes(fb)) diff --git a/tests/extmod/framebuf_subclass.py.exp b/tests/extmod/framebuf_subclass.py.exp new file mode 100644 index 0000000000..23d53ccc62 --- /dev/null +++ b/tests/extmod/framebuf_subclass.py.exp @@ -0,0 +1 @@ +b'\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x03\x04\x03\x04\x03' From c78ef92d787d7bab8acbec69e978037ec2b20d21 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 12 Dec 2017 15:22:03 +1100 Subject: [PATCH 125/828] py/objtype: Refactor object's handling of __new__ to not create 2 objs. Before this patch, if a user defined the __new__() function for a class then two instances of that class would be created: once before __new__ is called and once during the __new__ call (assuming the user creates some instance, eg using super().__new__, which is most of the time). The first one was then discarded. This refactor makes it so that a new instance is only created if the user __new__ function doesn't exist. --- py/objobject.c | 9 +++++--- py/objtype.c | 57 +++++++++++++++++++++++--------------------------- py/objtype.h | 5 +++++ 3 files changed, 37 insertions(+), 34 deletions(-) diff --git a/py/objobject.c b/py/objobject.c index 49d2ec62ee..265fcfbf2b 100644 --- a/py/objobject.c +++ b/py/objobject.c @@ -52,9 +52,12 @@ STATIC mp_obj_t object___new__(mp_obj_t cls) { if (!MP_OBJ_IS_TYPE(cls, &mp_type_type) || !mp_obj_is_instance_type((mp_obj_type_t*)MP_OBJ_TO_PTR(cls))) { mp_raise_TypeError("__new__ arg must be a user-type"); } - mp_obj_t o = MP_OBJ_SENTINEL; - mp_obj_t res = mp_obj_instance_make_new(MP_OBJ_TO_PTR(cls), 1, 0, &o); - return res; + // This executes only "__new__" part of instance creation. + // TODO: This won't work well for classes with native bases. + // TODO: This is a hack, should be resolved along the lines of + // https://github.com/micropython/micropython/issues/606#issuecomment-43685883 + const mp_obj_type_t *native_base; + return MP_OBJ_FROM_PTR(mp_obj_new_instance(MP_OBJ_TO_PTR(cls), &native_base)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___new___fun_obj, object___new__); STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(object___new___obj, MP_ROM_PTR(&object___new___fun_obj)); diff --git a/py/objtype.c b/py/objtype.c index 22c8f01bcb..33757287ac 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -90,17 +90,22 @@ STATIC mp_obj_t native_base_init_wrapper(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(native_base_init_wrapper_obj, 1, MP_OBJ_FUN_ARGS_MAX, native_base_init_wrapper); -STATIC mp_obj_t mp_obj_new_instance(const mp_obj_type_t *class, size_t subobjs) { - mp_obj_instance_t *o = m_new_obj_var(mp_obj_instance_t, mp_obj_t, subobjs); +#if !MICROPY_CPYTHON_COMPAT +STATIC +#endif +mp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *class, const mp_obj_type_t **native_base) { + size_t num_native_bases = instance_count_native_bases(class, native_base); + assert(num_native_bases < 2); + mp_obj_instance_t *o = m_new_obj_var(mp_obj_instance_t, mp_obj_t, num_native_bases); o->base.type = class; mp_map_init(&o->members, 0); // Initialise the native base-class slot (should be 1 at most) with a valid // object. It doesn't matter which object, so long as it can be uniquely // distinguished from a native class that is initialised. - if (subobjs != 0) { + if (num_native_bases != 0) { o->subobj[0] = MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj); } - return MP_OBJ_FROM_PTR(o); + return o; } // TODO @@ -267,20 +272,6 @@ STATIC void instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args) { assert(mp_obj_is_instance_type(self)); - const mp_obj_type_t *native_base = NULL; - size_t num_native_bases = instance_count_native_bases(self, &native_base); - assert(num_native_bases < 2); - - mp_obj_instance_t *o = MP_OBJ_TO_PTR(mp_obj_new_instance(self, num_native_bases)); - - // This executes only "__new__" part of instance creation. - // TODO: This won't work well for classes with native bases. - // TODO: This is a hack, should be resolved along the lines of - // https://github.com/micropython/micropython/issues/606#issuecomment-43685883 - if (n_args == 1 && *args == MP_OBJ_SENTINEL) { - return MP_OBJ_FROM_PTR(o); - } - // look for __new__ function mp_obj_t init_fn[2] = {MP_OBJ_NULL}; struct class_lookup_data lookup = { @@ -292,10 +283,12 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size }; mp_obj_class_lookup(&lookup, self); - mp_obj_t new_ret = MP_OBJ_FROM_PTR(o); - if (init_fn[0] == MP_OBJ_SENTINEL) { - // Native type's constructor is what wins - it gets all our arguments, - // and none Python classes are initialized at all. + const mp_obj_type_t *native_base = NULL; + mp_obj_instance_t *o; + if (init_fn[0] == MP_OBJ_NULL || init_fn[0] == MP_OBJ_SENTINEL) { + // Either there is no __new__() method defined or there is a native + // constructor. In both cases create a blank instance. + o = mp_obj_new_instance(self, &native_base); // Since type->make_new() implements both __new__() and __init__() in // one go, of which the latter may be overridden by the Python subclass, @@ -303,8 +296,9 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size // constructor to give a chance for the Python __init__() method to call // said native constructor. - } else if (init_fn[0] != MP_OBJ_NULL) { - // now call Python class __new__ function with all args + } else { + // Call Python class __new__ function with all args to create an instance + mp_obj_t new_ret; if (n_args == 0 && n_kw == 0) { mp_obj_t args2[1] = {MP_OBJ_FROM_PTR(self)}; new_ret = mp_call_function_n_kw(init_fn[0], 1, 0, args2); @@ -316,16 +310,17 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size m_del(mp_obj_t, args2, 1 + n_args + 2 * n_kw); } - } + // https://docs.python.org/3.4/reference/datamodel.html#object.__new__ + // "If __new__() does not return an instance of cls, then the new + // instance's __init__() method will not be invoked." + if (mp_obj_get_type(new_ret) != self) { + return new_ret; + } - // https://docs.python.org/3.4/reference/datamodel.html#object.__new__ - // "If __new__() does not return an instance of cls, then the new instance's __init__() method will not be invoked." - if (mp_obj_get_type(new_ret) != self) { - return new_ret; + // The instance returned by __new__() becomes the new object + o = MP_OBJ_TO_PTR(new_ret); } - o = MP_OBJ_TO_PTR(new_ret); - // now call Python class __init__ function with all args // This method has a chance to call super().__init__() to construct a // possible native base class. diff --git a/py/objtype.h b/py/objtype.h index 52419f3cdc..1f43130845 100644 --- a/py/objtype.h +++ b/py/objtype.h @@ -37,6 +37,11 @@ typedef struct _mp_obj_instance_t { // TODO maybe cache __getattr__ and __setattr__ for efficient lookup of them } mp_obj_instance_t; +#if MICROPY_CPYTHON_COMPAT +// this is needed for object.__new__ +mp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *cls, const mp_obj_type_t **native_base); +#endif + // this needs to be exposed for MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE to work void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest); From e4e3f0d7270e93e6123dbf05e1f51993e38d970c Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 12 Dec 2017 17:13:39 +1100 Subject: [PATCH 126/828] tests/cpydiff: Update subclassing Exception case and give work-around. --- tests/cpydiff/types_exception_subclassinit.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/cpydiff/types_exception_subclassinit.py b/tests/cpydiff/types_exception_subclassinit.py index 1770946462..56bab51d13 100644 --- a/tests/cpydiff/types_exception_subclassinit.py +++ b/tests/cpydiff/types_exception_subclassinit.py @@ -1,8 +1,12 @@ """ categories: Types,Exception -description: Exception.__init__ raises TypeError if overridden and called by subclass -cause: Unknown -workaround: Unknown +description: Exception.__init__ method does not exist. +cause: Subclassing native classes is not fully supported in MicroPython. +workaround: Call using ``super()`` instead:: + +class A(Exception): + def __init__(self): + super().__init__() """ class A(Exception): def __init__(self): From da34b6ef452514170e8ce1d1819070a920c2568e Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 12 Dec 2017 01:20:11 +0200 Subject: [PATCH 127/828] tests: Fix few test for proper "skipped" detection with qemu-arm's tinytest. "Builtin" tinytest-based testsuite as employed by qemu-arm (and now generalized by me to be reusable for other targets) performs simplified detection of skipped tests, it treats as such tests which raised SystemExit (instead of checking got "SKIP" output). Consequently, each "SKIP" must be accompanied by SystemExit (and conversely, SystemExit should not be used if test is not skipped, which so far seems to be true). --- tests/basics/builtin_compile.py | 1 + tests/basics/class_descriptor.py | 8 ++++---- tests/basics/fun_name.py | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/basics/builtin_compile.py b/tests/basics/builtin_compile.py index 32c6667d8b..bf272aca15 100644 --- a/tests/basics/builtin_compile.py +++ b/tests/basics/builtin_compile.py @@ -46,3 +46,4 @@ if have_compile(): test() else: print("SKIP") + raise SystemExit diff --git a/tests/basics/class_descriptor.py b/tests/basics/class_descriptor.py index eb88ba7b9c..54f386230f 100644 --- a/tests/basics/class_descriptor.py +++ b/tests/basics/class_descriptor.py @@ -27,8 +27,8 @@ except AttributeError: r = m.Forward if 'Descriptor' in repr(r.__class__): print('SKIP') -else: - print(r) - m.Forward = 'a' - del m.Forward + raise SystemExit +print(r) +m.Forward = 'a' +del m.Forward diff --git a/tests/basics/fun_name.py b/tests/basics/fun_name.py index 7a84fc3390..a724f41118 100644 --- a/tests/basics/fun_name.py +++ b/tests/basics/fun_name.py @@ -14,3 +14,4 @@ try: print(A().Fun.__name__) except AttributeError: print('SKIP') + raise SystemExit From 54cd6e3e4bb45f5ff649e3d31521f9a78015fb6b Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 13 Dec 2017 00:12:37 +0200 Subject: [PATCH 128/828] docs/packages: Add quick "Creating distribution packages" section. Needs more details. --- docs/reference/packages.rst | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/reference/packages.rst b/docs/reference/packages.rst index 28f5f9f487..d8d198e628 100644 --- a/docs/reference/packages.rst +++ b/docs/reference/packages.rst @@ -199,6 +199,32 @@ Few notes: you may want to decrease the amount of frozen modules included. +Creating distribution packages +------------------------------ + +Distribution packages for MicroPython are created in the same manner +as for CPython or any other Python implementation, see references at +the end of chapter. "Source distribution" (sdist) format is used for +packaging. The post-processing discussed above, (and pre-processing +discussed in the following section) is achieved by using custom +"sdist" command for distutils/setuptools. Thus, packaging steps +remain the same as for standard distutils/setuptools, the user just +need to override "sdist" command implementation by passing the +appropriate argument to ``setup()`` call:: + + from setuptools import setup + import sdist_upip + + setup( + ..., + cmdclass={'sdist': sdist_upip.sdist} + ) + +The sdist_upip.py module as referenced above can be found in +`micropython-lib`: +https://github.com/micropython/micropython-lib/blob/master/sdist_upip.py + + Application resources --------------------- From 479392a56e6edd8449e594c0e5c1e8f5176411ab Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Tue, 12 Dec 2017 08:13:48 +0000 Subject: [PATCH 129/828] drivers/display/ssd1306: Make SSD1306 class inherit from FrameBuffer. --- drivers/display/ssd1306.py | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/drivers/display/ssd1306.py b/drivers/display/ssd1306.py index cd358d00e2..cebe10e677 100644 --- a/drivers/display/ssd1306.py +++ b/drivers/display/ssd1306.py @@ -23,29 +23,16 @@ SET_PRECHARGE = const(0xd9) SET_VCOM_DESEL = const(0xdb) SET_CHARGE_PUMP = const(0x8d) - -class SSD1306: +# Subclassing FrameBuffer provides support for graphics primitives +# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html +class SSD1306(framebuf.FrameBuffer): def __init__(self, width, height, external_vcc): self.width = width self.height = height self.external_vcc = external_vcc self.pages = self.height // 8 self.buffer = bytearray(self.pages * self.width) - fb = framebuf.FrameBuffer(self.buffer, self.width, self.height, framebuf.MONO_VLSB) - self.framebuf = fb - # Provide methods for accessing FrameBuffer graphics primitives. This is a - # workround because inheritance from a native class is currently unsupported. - # http://docs.micropython.org/en/latest/pyboard/library/framebuf.html - self.fill = fb.fill - self.pixel = fb.pixel - self.hline = fb.hline - self.vline = fb.vline - self.line = fb.line - self.rect = fb.rect - self.fill_rect = fb.fill_rect - self.text = fb.text - self.scroll = fb.scroll - self.blit = fb.blit + super.__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) self.init_display() def init_display(self): From f1c9e7760d91cb141b0f03ee348b3fe36d2cf450 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 6 Mar 2017 16:46:34 +1100 Subject: [PATCH 130/828] py/builtinimport: Call __init__ for modules imported via a weak link. This is a bit of a clumsy way of doing it but solves the issue of __init__ not running when a module is imported via its weak-link name. Ideally a better solution would be found. --- py/builtinimport.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/py/builtinimport.c b/py/builtinimport.c index 2157902c95..97c1789f84 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -389,6 +389,19 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { } // found weak linked module module_obj = el->value; + if (MICROPY_MODULE_BUILTIN_INIT) { + // look for __init__ and call it if it exists + // Note: this code doesn't work fully correctly because it allows the + // __init__ function to be called twice if the module is imported by its + // non-weak-link name. Also, this code is duplicated in objmodule.c. + mp_obj_t dest[2]; + mp_load_method_maybe(el->value, MP_QSTR___init__, dest); + if (dest[0] != MP_OBJ_NULL) { + mp_call_method_n_kw(0, 0, dest); + // register module so __init__ is not called again + mp_module_register(mod_name, el->value); + } + } } else { no_exist: #else From bc08c884a2e7d1d3a4476c224f230b90ee2bf1e3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 6 Dec 2016 12:20:10 +1100 Subject: [PATCH 131/828] esp32: Add new port to Espressif ESP32 SoC. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit is a combination of 216 commits from the initial stages of development of this port, up to and including the point where the code was moved to the ports/esp32 directory. These commits were mostly concerned with setting up the build system and getting a reliable port working with basic features. The following is a digest of the original commits in their original order (most recent listed first), grouped where possible per author. The list is here to give credit for the work and provide some level of traceability and accountability. For the full history of development please consult the original repository. All code is MIT licensed and the relevant copyright holders are listed in the comment-header of each file. Damien George esp32: Update to latest ESP IDF. esp32: Update module symlinks now that code lives under the ports dir. esp32: Update to compile with new ports/esp32 directory structure. esp32: Move it to the ports/ directory. esp32/machine_uart: Don't save baudrate but compute it instead. esp32/modsocket: Add socket.readinto() method. esp32/modesp: Add esp.gpio_matrix_in and esp.gpio_matrix_out functions. esp32/machine_uart: Wait for all data to be tx'd before changing config. NyxCode esp32: Add note to README.md about updating the submodules of ESP IDF. Anthony Briggs esp32: Update README.md installation and flashing instructions. Javier Candeira esp32: Raise error when setting input-only pin to output. With help from Adrian Smith (fon@thefon.net) Javier Candeira esp32: Replace exception raising with corresponding mp_raise_XXX funcs. Tisham Dhar esp32: Add some specific notes about building on Windows using WSL. Ben Gamari esp32: Provide machine.Signal class. Damien George esp32/modnetwork: Implement AP version of network.isconnected(). Eric Poulsen esp32/README.md: Add note about btree submodule initialization. Damien George esp32: Make firmware.bin start at 0x1000 to allow flash size autodetect. esp32: Changes to follow latest version of upstream uPy. esp32/Makefile: Separate ESP-specific inc dirs to avoid header clashes. esp32: Enable "btree" database module. esp32: Update to latest ESP IDF. Roosted7 esp32: Update to latest ESP-IDF. Alex King esp32/machine_timer: Add support for esp32 hardware timer. Code lineage: Timer() is based loosely on the version in esp8266, although the implementation is differs significantly because of the change in the underlying platform. Damien George esp32/machine_uart: Increase UART TX buffer size to 64. esp32/modules: Update dht symlink. esp32/mpconfigport.h: Enable utimeq module, needed for uasyncio. esp32: Changes to follow latest version of upstream uPy. esp32: Update to latest ESP-IDF. esp32/machine_uart: Add uart.any() method. esp32/machine_uart: Uninstall the UART driver before installing it. Thomas Roos esp32: Update to latest ESP-IDF. Eric Poulsen esp32/modsocket: Make read/write return None when in non-blocking mode. esp32/modsocket.c: Fix send/sendto/write for non-blocking sockets. Odd Stråbø esp32: Initial working implementation of machine.UART. Code lineage (as seen by previous commits): I copied the ESP8266 code, renamed pyb -> machine, and used esp-idf as a reference while implementing minimal functionality. I provide all of my changes under the MIT license. Odd Stråbø esp32/machine_uart: Rename pyb to machine. esp32: Copy machine_uart.c from esp8266 port. Damien George esp32/moduos: Add uos.ilistdir() function. esp32: Mount filesystem at the root of the VFS, following esp8266. Andy Valencia esp32: Add hardware SHA1/SHA256 support via mbedtls API. Code lineage: a copy of extmod/moduhashlib with the API invocation details edited. Total derivative work. Andy Valencia esp32: Add PWM support via machine.PWM class. Code lineage: I started by copying the esp8266 machine_pwm.c. I used information from the ESP32 Technical Reference Manual, the esp-idf documentation, and the SDK's sample ledc example code (but I did not copy that code, just studied it to understand the SDK's API for PWM). So aside from the code copied from the esp8266 PWM support, everything else you see is just new code I wrote. I wasn't an employee of anybody when I wrote it, and I wrote it with the understanding and intention that it's simply a derivative work of the existing micropython code. I freely and willingly contribute it to the project and intend that it not change the legal status of the micropython code base in any way, even if it is included in that base in whole or part. Damien George esp32/modules: Add symlinks for upysh and upip. Eric Poulsen esp32/modmachine: Add unique_id() function to machine module. Damien George esp32: Change dac_out_voltage to dac_output_voltage for new IDF API. esp32: Update esp32.custom_common.ld to align with changes in ESP IDF. Eric Poulsen esp32: Update to latest ESP IDF. Damien George esp32/modsocket: When resolving IP addr handle the case of host=''. esp32: Update to latest ESP IDF. Eric Poulsen esp32/Makefile: Change default FLASH_MODE to dio for WROOM-32 module. esp32: Move FAT FS to start at 0x200000 and increase size to 2MiB. Damien George esp32: Remove enable_irq/disable_irq and use ATOMIC_SECTION instead. esp32/mpconfigport.h: Provide ATOMIC_SECTION macros. esp32/main: Restart the MCU if there is a failed NLR jump. Daniel Campora esp32: Enable threading; be sure to exit GIL when a thread will block. esp32: Trace the registers when doing a gc collect. Also make it thread ready. esp32: Add threading implementation, disabled for the time being. Damien George esp32: Update to latest ESP IDF. esp32/uart: Use high-level function to install UART0 RX ISR handler. esp32/Makefile: Make FreeRTOS private include dir really private. Eric Poulsen esp32: Add support for hardware SPI peripheral (block 1 and 2). Sergio Conde Gómez esp32/modules/inisetup.py: Mount filesystem at /flash like ESP8266 Damien George esp32: Convert to use core-provided KeyboardInterrupt exception. esp32: Pump the event loop while waiting for rx-chr or delay_ms. esp32: Implement Pin.irq() using "soft" scheduled interrupts. esp32: Update to latest ESP IDF version. Eric Poulsen esp32/README: Add troubleshooting section to the end. tyggerjai esp32: Add support for WS2812 and APA106 RGB LEDs. Damien George esp32: Add makeimg.py script to build full firmware; use it in Makefile. esp32/modsocket: Make socket.read return when socket closes. esp32/modsocket: Initialise the timeout on an accepted socket. esp32/mphalport: Provide proper implementations of disable_/enable_irq. esp32/modmachine: Add disable_irq/enable_irq functions. Nick Moore esp32/modsocket.c: add comment explaining timeout behaviour esp32/modsocket.c: clean up send methods for retries too esp32/modsocket.c: sockets always nonblocking, accept timeout in modsocket esp32: Update to latest ESP IDF version. esp32/modsocket.c: remove MSG_PEEK workaround on select ioctl. esp32/modsocket.c: Initialize tcp when modsocket loads. Damien George esp32/main: Bump heap size from 64k to 96k. esp32/modutime: Add time.time() function. esp32/modsocket: Convert lwip errnos to uPy ones. esp32/modules: Provide symlink to ds18x20 module. esp32: Add support for onewire protocol via OneWire module. esp32: Add support for DHT11 and DHT22 sensors. esp32/mphalport: Improve delay and ticks functions. esp32: Update to latest ESP IDF. esp32/modules: Provide symlink to urequests from micropython-lib. esp32: Populate sys.path. Nick Moore esp32/machine_dac.c: implement DAC pins as well esp32/machine_adc.c: also machine.ADC esp32/machine_touchpad.c: add support for touchpad Damien George esp32/README: Add hint about using GNUmakefile on case-insensitive FS. esp32/mpconfigport.h: Enable maximum speed software SPI. esp32: Provide improved version of mp_hal_delay_us_fast. esp32/mpconfigport.h: Enable MICROPY_PY_BUILTINS_POW3 option. esp32: Update to latest ESP IDF. esp32: Convert to use new oofatfs library and generic VFS sub-system. esp32: Enable help('modules') to list builtin modules. esp32: Convert to use new builtin help function. Aaron Kelly esp32/README: Add comment about ESP-IDF version Damien George esp32: Consistently use size_t instead of mp_uint_t. esp32: Change "Micro Python" to "MicroPython" in license comments. esp32/Makefile: Use -C argument to git instead of cd'ing. esp32/help: Add section to help about using the network module. esp32/README: Add section about configuring and using an ESP32 board. esp32/README: Remove paragraph about buggy toolchain, it's now fixed. esp32/modnetwork: Change network init logging from info to debug. esp32/modnetwork: Don't start AP automatically when init'ing wifi. esp32/modsocket: Implement socket.setsockopt, to support SO_REUSEADDR. esp32: Update to latest ESP IDF. esp32/sdkconfig.h: Remove unused CONFIG_ESPTOOLPY_xxx config settings. esp32/modsocket: Add support for DGRAM and RAW, and sendto/recvfrom. esp32/modsocket: Fix return value of "port" in socket.accept. esp32/modsocket: Make socket.recv take exactly 2 args. esp32: Enable ussl module, using mbedtls component from ESP IDF. esp32/modsocket: Rename "socket" module to "usocket". esp32/sdkconfig: Increase max number of open sockets from 4 to 8. esp32/modsocket: Add error checking for creating and closing sockets. esp32/modsocket: Use _r (re-entrant) versions of LWIP socket API funcs. esp32/modsocket: Raise an exception if socket.connect did not succeed. esp32/modsocket: Make socket.accept return a tuple: (client, addr). esp32/modsocket: Use m_new_obj_with_finaliser instead of calloc. esp32/Makefile: Add check for IDF version, and warn if not supported. esp32/esp32.custom_common.ld: Update to follow changes in IDF. esp32: Update to latest ESP IDF. nubcore esp32: add #define CONFIG_ESP32_WIFI_RX_BUFFER_NUM 25 Nick Moore esp32/modsocket.c: add in sendall and makefile methods #10 esp32/modsocket.c: fixups for #10 esp32/modsocket.c: fix copyright, socket_recv gets param and exception esp32/modnetwork.c: fix copyright, network.active param to bool Damien George esp32/modnetwork: Implement wlan.isconnected() method. esp32/modnetwork: Add initial implementation of wlan.config(). esp32/modnetwork: Simplify event_handler messages. Nick Moore esp32/modsocket.c: support for ioctl, settimeout, setblocking, getaddrinfo Damien George esp32/README: Add comment about FLASH_MODE being dio. esp32: Update to latest ESP IDF. esp32/modnetwork: Remove unnecessary indirection variable for scan list. esp32/modnetwork: Check that STA is active before trying to scan. esp32/mphalport: Replace portTICK_RATE_MS with portTICK_PERIOD_MS. esp32/README: Add comment about using $(HOME) in makefile. esp32/modnetwork: Use memset instead of bzero, the latter is deprecated. esp32/modnetwork: Improve error handling when STA is connecting to AP. esp32/Makefile: Use tab instead of spaces, and use shorter variable. Nick Moore esp32/modsocket.c: AF_*, SOCK_* and IPPROTO_* constants esp32/modsocket.c: socket.settimeout implementation Damien George esp32/Makefile: Update to latest ESP IDF. Nick Moore esp32/modsocket.c: use mp streams for sockets esp32: network.WLAN.ifconfig based on esp8266 version esp32: Fix up exception handling esp32: sketchy modsocket ... revisit this once modnetwork is sorted esp32: First cut at modnetwork, manually rebased from prev. version Damien George esp32/help: Update help text. esp32: Add info about Microbric Pty Ltd being the sponsor of this port. esp32: Add README.md file. esp32/mpconfigport.h: Add weak links to many of the builtin modules. esp32: Enable soft implementation of machine.SPI class. esp32/Makefile: Simplify APP_LD_ARGS by using OBJ variable. esp32/Makefile: Reorganise Makefile and add some comments. esp32/Makefile: Clean up CFLAGS for ESP IDF components. esp32/Makefile: Tidy up names of ESP IDF components, to match dir name. esp32/Makefile: Define and use ESPCOMP variable. esp32: Update to latest ESP IDF. esp32/main: Enable filesystem support. esp32: Use custom ld script to ensure correct code get placed in iram. esp32: Update to latest ESP IDF. esp32/main: Pin the uPy task to core 0. esp32: Update to use latest ESP IDF. esp32: Disable boot-up scripts, spi_flash_erase_sector no longer works. esp32: Add scripts to init and mount filesystem. esp32: Enable frozen bytecode, with scripts stored in "modules/" dir. esp32/modesp: Increase flash_user_start position to 1Mbyte. esp32/Makefile: Add "erase" target for convenient erasure. esp32/sdkconfig: Reorder config settings to put common things together. esp32/sdkconfig: Change to use single core only. esp32: Add esp module. esp32/uart.c: Make sure uart ISR handler is all in iram. esp32/main.c: Use ESP_TASK_PRIO_MIN + 1 for mp_task's priority. esp32/Makefile: Use only bare-minimum flags when compiling .S files. esp32/Makefile: Rename "firmware" to "application". esp32: Update ESP IDF version. esp32/Makefile: Add declarations to build bootloader and partitions. esp32/Makefile: When deploying, write the application last. esp32/Makefile: Use $(INC) variable instead of listing include dirs. esp32/Makefile: Use locally built versions of freertos and newlib libs. esp32: Add low-level uart handler with ISR and ringbuf for stdin. esp32: Add machine.idle() function. esp32: Add machine.I2C class. esp32: Enable machine.time_pulse_us. esp32: Add initial implementation of machine.Pin class. esp32: Prepare main.c for using xTaskCreateStatic. esp32: Clean up mphalport.h. esp32: Add initial uos module. esp32: Clean up mpconfigport.h, enable more features. esp32: Use new reset function. esp32: Update to latest ESP IDF. esp32: Add idf-version target to Makefile, to track IDF commit. esp32: Initial port to ESP32. --- ports/esp32/Makefile | 719 +++++++++++++++++++++++++++ ports/esp32/README.md | 199 ++++++++ ports/esp32/esp32.custom_common.ld | 215 ++++++++ ports/esp32/espneopixel.c | 53 ++ ports/esp32/esponewire.c | 80 +++ ports/esp32/fatfs_port.c | 46 ++ ports/esp32/gccollect.c | 66 +++ ports/esp32/gccollect.h | 42 ++ ports/esp32/help.c | 65 +++ ports/esp32/machine_adc.c | 132 +++++ ports/esp32/machine_dac.c | 97 ++++ ports/esp32/machine_hw_spi.c | 370 ++++++++++++++ ports/esp32/machine_pin.c | 375 ++++++++++++++ ports/esp32/machine_pwm.c | 277 +++++++++++ ports/esp32/machine_timer.c | 192 +++++++ ports/esp32/machine_touchpad.c | 110 ++++ ports/esp32/machine_uart.c | 359 +++++++++++++ ports/esp32/main.c | 131 +++++ ports/esp32/makeimg.py | 25 + ports/esp32/memory.h | 2 + ports/esp32/modesp.c | 129 +++++ ports/esp32/modesp.h | 1 + ports/esp32/modmachine.c | 135 +++++ ports/esp32/modmachine.h | 18 + ports/esp32/modnetwork.c | 561 +++++++++++++++++++++ ports/esp32/modsocket.c | 570 +++++++++++++++++++++ ports/esp32/moduhashlib.c | 142 ++++++ ports/esp32/modules/_boot.py | 12 + ports/esp32/modules/apa106.py | 8 + ports/esp32/modules/dht.py | 1 + ports/esp32/modules/ds18x20.py | 1 + ports/esp32/modules/flashbdev.py | 34 ++ ports/esp32/modules/inisetup.py | 38 ++ ports/esp32/modules/neopixel.py | 33 ++ ports/esp32/modules/onewire.py | 1 + ports/esp32/modules/upip.py | 1 + ports/esp32/modules/upip_utarfile.py | 1 + ports/esp32/modules/upysh.py | 1 + ports/esp32/modules/urequests.py | 1 + ports/esp32/moduos.c | 128 +++++ ports/esp32/modutime.c | 61 +++ ports/esp32/mpconfigport.h | 248 +++++++++ ports/esp32/mphalport.c | 139 ++++++ ports/esp32/mphalport.h | 83 ++++ ports/esp32/mpthreadport.c | 226 +++++++++ ports/esp32/mpthreadport.h | 45 ++ ports/esp32/qstrdefsport.h | 30 ++ ports/esp32/sdkconfig.h | 162 ++++++ ports/esp32/uart.c | 65 +++ ports/esp32/uart.h | 33 ++ 50 files changed, 6463 insertions(+) create mode 100644 ports/esp32/Makefile create mode 100644 ports/esp32/README.md create mode 100644 ports/esp32/esp32.custom_common.ld create mode 100644 ports/esp32/espneopixel.c create mode 100644 ports/esp32/esponewire.c create mode 100644 ports/esp32/fatfs_port.c create mode 100644 ports/esp32/gccollect.c create mode 100644 ports/esp32/gccollect.h create mode 100644 ports/esp32/help.c create mode 100644 ports/esp32/machine_adc.c create mode 100644 ports/esp32/machine_dac.c create mode 100644 ports/esp32/machine_hw_spi.c create mode 100644 ports/esp32/machine_pin.c create mode 100644 ports/esp32/machine_pwm.c create mode 100644 ports/esp32/machine_timer.c create mode 100644 ports/esp32/machine_touchpad.c create mode 100644 ports/esp32/machine_uart.c create mode 100644 ports/esp32/main.c create mode 100644 ports/esp32/makeimg.py create mode 100644 ports/esp32/memory.h create mode 100644 ports/esp32/modesp.c create mode 100644 ports/esp32/modesp.h create mode 100644 ports/esp32/modmachine.c create mode 100644 ports/esp32/modmachine.h create mode 100644 ports/esp32/modnetwork.c create mode 100644 ports/esp32/modsocket.c create mode 100644 ports/esp32/moduhashlib.c create mode 100644 ports/esp32/modules/_boot.py create mode 100644 ports/esp32/modules/apa106.py create mode 120000 ports/esp32/modules/dht.py create mode 120000 ports/esp32/modules/ds18x20.py create mode 100644 ports/esp32/modules/flashbdev.py create mode 100644 ports/esp32/modules/inisetup.py create mode 100644 ports/esp32/modules/neopixel.py create mode 120000 ports/esp32/modules/onewire.py create mode 120000 ports/esp32/modules/upip.py create mode 120000 ports/esp32/modules/upip_utarfile.py create mode 120000 ports/esp32/modules/upysh.py create mode 120000 ports/esp32/modules/urequests.py create mode 100644 ports/esp32/moduos.c create mode 100644 ports/esp32/modutime.c create mode 100644 ports/esp32/mpconfigport.h create mode 100644 ports/esp32/mphalport.c create mode 100644 ports/esp32/mphalport.h create mode 100644 ports/esp32/mpthreadport.c create mode 100644 ports/esp32/mpthreadport.h create mode 100644 ports/esp32/qstrdefsport.h create mode 100644 ports/esp32/sdkconfig.h create mode 100644 ports/esp32/uart.c create mode 100644 ports/esp32/uart.h diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile new file mode 100644 index 0000000000..2eae802be5 --- /dev/null +++ b/ports/esp32/Makefile @@ -0,0 +1,719 @@ +include ../../py/mkenv.mk + +# qstr definitions (must come before including py.mk) +QSTR_DEFS = qstrdefsport.h + +MICROPY_PY_USSL = 0 +MICROPY_SSL_AXTLS = 0 +MICROPY_FATFS = 1 +MICROPY_PY_BTREE = 1 + +#FROZEN_DIR = scripts +FROZEN_MPY_DIR = modules + +# include py core make definitions +include $(TOP)/py/py.mk + +PORT ?= /dev/ttyUSB0 +BAUD ?= 460800 +FLASH_MODE ?= dio +FLASH_FREQ ?= 40m +FLASH_SIZE ?= 4MB +CROSS_COMPILE ?= xtensa-esp32-elf- + +# paths to ESP IDF and its components +ifeq ($(ESPIDF),) +$(error Please configure the ESPIDF variable) +endif +ESPCOMP = $(ESPIDF)/components +ESPTOOL ?= $(ESPCOMP)/esptool_py/esptool/esptool.py + +# verify the ESP IDF version +ESPIDF_SUPHASH := 9a26296a0e88a4c3ae27e9c848be970946fff87e +ESPIDF_CURHASH := $(shell git -C $(ESPIDF) show -s --pretty=format:'%H') +ifneq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH)) +$(info ** WARNING **) +$(info The git hash of ESP IDF does not match the supported version) +$(info The build may complete and the firmware may work but it is not guaranteed) +$(info ESP IDF path: $(ESPIDF)) +$(info Current git hash: $(ESPIDF_CURHASH)) +$(info Supported git hash: $(ESPIDF_SUPHASH)) +endif + +# pretty format of ESP IDF version, used internally by the IDF +IDF_VER := $(shell git -C $(ESPIDF) describe) + +INC += -I. +INC += -I$(TOP) +INC += -I$(TOP)/lib/mp-readline +INC += -I$(TOP)/lib/netutils +INC += -I$(TOP)/lib/timeutils +INC += -I$(BUILD) + +INC_ESPCOMP += -I$(ESPCOMP)/bootloader_support/include +INC_ESPCOMP += -I$(ESPCOMP)/driver/include +INC_ESPCOMP += -I$(ESPCOMP)/driver/include/driver +INC_ESPCOMP += -I$(ESPCOMP)/nghttp/port/include +INC_ESPCOMP += -I$(ESPCOMP)/nghttp/nghttp2/lib/includes +INC_ESPCOMP += -I$(ESPCOMP)/esp32/include +INC_ESPCOMP += -I$(ESPCOMP)/soc/include +INC_ESPCOMP += -I$(ESPCOMP)/soc/esp32/include +INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include +INC_ESPCOMP += -I$(ESPCOMP)/expat/include/expat +INC_ESPCOMP += -I$(ESPCOMP)/expat/port/include +INC_ESPCOMP += -I$(ESPCOMP)/heap/include +INC_ESPCOMP += -I$(ESPCOMP)/json/include +INC_ESPCOMP += -I$(ESPCOMP)/json/port/include +INC_ESPCOMP += -I$(ESPCOMP)/log/include +INC_ESPCOMP += -I$(ESPCOMP)/newlib/include +INC_ESPCOMP += -I$(ESPCOMP)/nvs_flash/include +INC_ESPCOMP += -I$(ESPCOMP)/freertos/include +INC_ESPCOMP += -I$(ESPCOMP)/tcpip_adapter/include +INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip +INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip/port +INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip/posix +INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/include +INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/port/include +INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/include +INC_ESPCOMP += -I$(ESPCOMP)/vfs/include +INC_ESPCOMP += -I$(ESPCOMP)/newlib/platform_include +INC_ESPCOMP += -I$(ESPCOMP)/xtensa-debug-module/include +INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/include +INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/port/include +INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include +INC_ESPCOMP += -I$(ESPCOMP)/app_trace/include + +CFLAGS_BASE = -std=gnu99 -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -mlongcalls -nostdlib -Wall -Werror -Wno-error=unused-function -Wno-error=unused-but-set-variable -Wno-error=unused-variable -Wno-error=deprecated-declarations -DMBEDTLS_CONFIG_FILE='"mbedtls/esp_config.h"' -DHAVE_CONFIG_H -DESP_PLATFORM +CFLAGS = $(CFLAGS_BASE) $(INC) $(INC_ESPCOMP) +CFLAGS += -DIDF_VER=\"$(IDF_VER)\" +CFLAGS += $(CFLAGS_MOD) + +# this is what ESPIDF uses for c++ compilation +CXXFLAGS = -std=gnu++11 -fno-exceptions -fno-rtti -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -mlongcalls -nostdlib -Wall -Werror -Wno-error=unused-function -Wno-error=unused-but-set-variable -Wno-error=unused-variable -Wno-error=deprecated-declarations -DESP_PLATFORM $(INC) $(INC_ESPCOMP) + +LDFLAGS = -nostdlib -Map=$(@:.elf=.map) --cref +LDFLAGS += --gc-sections -static -EL +LDFLAGS += -u call_user_start_cpu0 -u uxTopUsedPriority -u ld_include_panic_highint_hdl +LDFLAGS += -u __cxa_guard_dummy # so that implementation of static guards is taken from cxx_guards.o instead of libstdc++.a +LDFLAGS += -L$(ESPCOMP)/esp32/ld +LDFLAGS += -T $(BUILD)/esp32_out.ld +LDFLAGS += -T ./esp32.custom_common.ld +LDFLAGS += -T esp32.rom.ld +LDFLAGS += -T esp32.rom.spiram_incompatible_fns.ld +LDFLAGS += -T esp32.peripherals.ld + +LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) +LIBSTDCXX_FILE_NAME = $(shell $(CXX) $(CXXFLAGS) -print-file-name=libstdc++.a) + +# Debugging/Optimization +ifeq ($(DEBUG), 1) +CFLAGS += -g +COPT = -O0 +else +#CFLAGS += -fdata-sections -ffunction-sections +COPT += -Os -DNDEBUG +#LDFLAGS += --gc-sections +endif + +################################################################################ +# List of MicroPython source and object files + +SRC_C = \ + main.c \ + uart.c \ + gccollect.c \ + mphalport.c \ + fatfs_port.c \ + help.c \ + modutime.c \ + moduos.c \ + machine_timer.c \ + machine_pin.c \ + machine_touchpad.c \ + machine_adc.c \ + machine_dac.c \ + machine_pwm.c \ + machine_uart.c \ + modmachine.c \ + modnetwork.c \ + modsocket.c \ + modesp.c \ + moduhashlib.c \ + espneopixel.c \ + machine_hw_spi.c \ + mpthreadport.c \ + $(SRC_MOD) + +EXTMOD_SRC_C = $(addprefix extmod/,\ + modonewire.c \ + ) + +LIB_SRC_C = $(addprefix lib/,\ + libm/math.c \ + libm/fmodf.c \ + libm/roundf.c \ + libm/ef_sqrt.c \ + libm/kf_rem_pio2.c \ + libm/kf_sin.c \ + libm/kf_cos.c \ + libm/kf_tan.c \ + libm/ef_rem_pio2.c \ + libm/sf_sin.c \ + libm/sf_cos.c \ + libm/sf_tan.c \ + libm/sf_frexp.c \ + libm/sf_modf.c \ + libm/sf_ldexp.c \ + libm/asinfacosf.c \ + libm/atanf.c \ + libm/atan2f.c \ + mp-readline/readline.c \ + netutils/netutils.c \ + timeutils/timeutils.c \ + utils/pyexec.c \ + utils/interrupt_char.c \ + utils/sys_stdio_mphal.c \ + ) + +ifeq ($(MICROPY_FATFS), 1) +LIB_SRC_C += \ + lib/oofatfs/ff.c \ + lib/oofatfs/option/unicode.c +endif + +DRIVERS_SRC_C = $(addprefix drivers/,\ + dht/dht.c \ + ) + +OBJ_MP = +OBJ_MP += $(PY_O) +OBJ_MP += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ_MP += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o)) +OBJ_MP += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) +OBJ_MP += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) + +# List of sources for qstr extraction +SRC_QSTR += $(SRC_C) $(EXTMOD_SRC_C) $(LIB_SRC_C) $(DRIVERS_SRC_C) +# Append any auto-generated sources that are needed by sources listed in SRC_QSTR +SRC_QSTR_AUTO_DEPS += + +################################################################################ +# List of object files from the ESP32 IDF components + +ESPIDF_DRIVER_O = $(addprefix $(ESPCOMP)/driver/,\ + uart.o \ + periph_ctrl.o \ + ledc.o \ + gpio.o \ + timer.o \ + spi_master.o \ + spi_common.o \ + rtc_module.o \ + ) + +$(BUILD)/$(ESPCOMP)/esp32/dport_access.o: CFLAGS += -Wno-array-bounds +ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\ + panic.o \ + esp_timer.o \ + esp_timer_esp32.o \ + ets_timer_legacy.o \ + event_default_handlers.o \ + fast_crypto_ops.o \ + task_wdt.o \ + cache_err_int.o \ + clk.o \ + core_dump.o \ + cpu_start.o \ + gdbstub.o \ + crosscore_int.o \ + ipc.o \ + int_wdt.o \ + event_loop.o \ + hwcrypto/sha.o \ + hwcrypto/aes.o \ + lib_printf.o \ + freertos_hooks.o \ + system_api.o \ + hw_random.o \ + phy_init.o \ + intr_alloc.o \ + dport_access.o \ + wifi_init.o \ + ) + +ESPIDF_HEAP_O = $(addprefix $(ESPCOMP)/heap/,\ + heap_caps.o \ + heap_caps_init.o \ + multi_heap.o \ + ) + +ESPIDF_SOC_O = $(addprefix $(ESPCOMP)/soc/,\ + esp32/cpu_util.o \ + esp32/rtc_clk.o \ + esp32/rtc_init.o \ + esp32/rtc_pm.o \ + esp32/rtc_sleep.o \ + esp32/rtc_time.o \ + esp32/soc_memory_layout.o \ + ) + +ESPIDF_CXX_O = $(addprefix $(ESPCOMP)/cxx/,\ + cxx_guards.o \ + ) + +ESPIDF_ETHERNET_O = $(addprefix $(ESPCOMP)/ethernet/,\ + emac_dev.o \ + emac_main.o \ + ) + +$(BUILD)/$(ESPCOMP)/expat/%.o: CFLAGS += -Wno-unused-function +ESPIDF_EXPAT_O = $(addprefix $(ESPCOMP)/expat/,\ + library/xmltok_ns.o \ + library/xmltok.o \ + library/xmlparse.o \ + library/xmlrole.o \ + library/xmltok_impl.o \ + port/minicheck.o \ + port/expat_element.o \ + port/chardata.o \ + ) + +ESPIDF_PTHREAD_O = $(addprefix $(ESPCOMP)/pthread/,\ + pthread.o \ + ) + +# Assembler .S files need only basic flags, and in particular should not have +# -Os because that generates subtly different code. +# We also need custom CFLAGS for .c files because FreeRTOS has headers with +# generic names (eg queue.h) which can clash with other files in the port. +CFLAGS_ASM = -I$(ESPCOMP)/esp32/include -I$(ESPCOMP)/soc/esp32/include -I$(ESPCOMP)/freertos/include/freertos -I. +$(BUILD)/$(ESPCOMP)/freertos/portasm.o: CFLAGS = $(CFLAGS_ASM) +$(BUILD)/$(ESPCOMP)/freertos/xtensa_context.o: CFLAGS = $(CFLAGS_ASM) +$(BUILD)/$(ESPCOMP)/freertos/xtensa_intr_asm.o: CFLAGS = $(CFLAGS_ASM) +$(BUILD)/$(ESPCOMP)/freertos/xtensa_vectors.o: CFLAGS = $(CFLAGS_ASM) +$(BUILD)/$(ESPCOMP)/freertos/%.o: CFLAGS = $(CFLAGS_BASE) -I. $(INC_ESPCOMP) -I$(ESPCOMP)/freertos/include/freertos +ESPIDF_FREERTOS_O = $(addprefix $(ESPCOMP)/freertos/,\ + croutine.o \ + event_groups.o \ + FreeRTOS-openocd.o \ + list.o \ + portasm.o \ + port.o \ + queue.o \ + ringbuf.o \ + tasks.o \ + timers.o \ + xtensa_context.o \ + xtensa_init.o \ + xtensa_intr_asm.o \ + xtensa_intr.o \ + xtensa_overlay_os_hook.o \ + xtensa_vector_defaults.o \ + xtensa_vectors.o \ + ) + +ESPIDF_VFS_O = $(addprefix $(ESPCOMP)/vfs/,\ + vfs_uart.o \ + vfs.o \ + ) + +ESPIDF_JSON_O = $(addprefix $(ESPCOMP)/json/,\ + library/cJSON.o \ + port/cJSON_Utils.o \ + ) + +ESPIDF_LOG_O = $(addprefix $(ESPCOMP)/log/,\ + log.o \ + ) + +ESPIDF_XTENSA_DEBUG_MODULE_O = $(addprefix $(ESPCOMP)/xtensa-debug-module/,\ + eri.o \ + trax.o \ + ) + +ESPIDF_TCPIP_ADAPTER_O = $(addprefix $(ESPCOMP)/tcpip_adapter/,\ + tcpip_adapter_lwip.o \ + ) + +ESPIDF_APP_TRACE_O = $(addprefix $(ESPCOMP)/app_trace/,\ + app_trace.o \ + ) + +ESPIDF_NEWLIB_O = $(addprefix $(ESPCOMP)/newlib/,\ + time.o \ + syscalls.o \ + syscall_table.o \ + reent_init.o \ + locks.o \ + ) + +ESPIDF_NGHTTP_O = $(addprefix $(ESPCOMP)/nghttp/,\ + nghttp2/lib/nghttp2_http.o \ + nghttp2/lib/nghttp2_version.o \ + nghttp2/lib/nghttp2_mem.o \ + nghttp2/lib/nghttp2_hd_huffman.o \ + nghttp2/lib/nghttp2_rcbuf.o \ + nghttp2/lib/nghttp2_callbacks.o \ + nghttp2/lib/nghttp2_session.o \ + nghttp2/lib/nghttp2_stream.o \ + nghttp2/lib/nghttp2_hd.o \ + nghttp2/lib/nghttp2_priority_spec.o \ + nghttp2/lib/nghttp2_buf.o \ + nghttp2/lib/nghttp2_option.o \ + nghttp2/lib/nghttp2_npn.o \ + nghttp2/lib/nghttp2_helper.o \ + nghttp2/lib/nghttp2_frame.o \ + nghttp2/lib/nghttp2_outbound_item.o \ + nghttp2/lib/nghttp2_hd_huffman_data.o \ + nghttp2/lib/nghttp2_pq.o \ + nghttp2/lib/nghttp2_queue.o \ + nghttp2/lib/nghttp2_submit.o \ + nghttp2/lib/nghttp2_map.o \ + port/http_parser.o \ + ) + +ESPIDF_NVS_FLASH_O = $(addprefix $(ESPCOMP)/nvs_flash/,\ + src/nvs_types.o \ + src/nvs_page.o \ + src/nvs_item_hash_list.o \ + src/nvs_pagemanager.o \ + src/nvs_storage.o \ + src/nvs_api.o \ + ) + +ESPIDF_OPENSSL_O = $(addprefix $(ESPCOMP)/openssl/,\ + ) + +ESPIDF_SPI_FLASH_O = $(addprefix $(ESPCOMP)/spi_flash/,\ + flash_mmap.o \ + partition.o \ + spi_flash_rom_patch.o \ + cache_utils.o \ + flash_ops.o \ + ) + +$(BUILD)/$(ESPCOMP)/lwip/%.o: CFLAGS += -Wno-address -Wno-unused-variable -Wno-unused-but-set-variable +ESPIDF_LWIP_O = $(addprefix $(ESPCOMP)/lwip/,\ + api/pppapi.o \ + api/netbuf.o \ + api/api_lib.o \ + api/netifapi.o \ + api/tcpip.o \ + api/netdb.o \ + api/err.o \ + api/api_msg.o \ + api/sockets.o \ + apps/sntp/sntp.o \ + apps/dhcpserver.o \ + core/ipv4/ip_frag.o \ + core/ipv4/dhcp.o \ + core/ipv4/ip4_addr.o \ + core/ipv4/igmp.o \ + core/ipv4/ip4.o \ + core/ipv4/autoip.o \ + core/ipv4/icmp.o \ + core/ipv6/ip6_frag.o \ + core/ipv6/dhcp6.o \ + core/ipv6/inet6.o \ + core/ipv6/ip6_addr.o \ + core/ipv6/ip6.o \ + core/ipv6/nd6.o \ + core/ipv6/mld6.o \ + core/ipv6/ethip6.o \ + core/ipv6/icmp6.o \ + core/mem.o \ + core/init.o \ + core/memp.o \ + core/sys.o \ + core/tcp_in.o \ + core/dns.o \ + core/ip.o \ + core/pbuf.o \ + core/raw.o \ + core/tcp.o \ + core/def.o \ + core/netif.o \ + core/stats.o \ + core/timers.o \ + core/inet_chksum.o \ + core/udp.o \ + core/tcp_out.o \ + netif/slipif.o \ + netif/etharp.o \ + netif/ethernet.o \ + netif/lowpan6.o \ + netif/ethernetif.o \ + port/freertos/sys_arch.o \ + port/netif/wlanif.o \ + port/netif/ethernetif.o \ + ) + +ESPIDF_MBEDTLS_O = $(addprefix $(ESPCOMP)/mbedtls/,\ + library/entropy.o \ + library/pkcs12.o \ + library/ccm.o \ + library/pk.o \ + library/sha1.o \ + library/x509_csr.o \ + library/ssl_cli.o \ + library/ecp.o \ + library/blowfish.o \ + library/x509.o \ + library/ecp_curves.o \ + library/error.o \ + library/ssl_ticket.o \ + library/entropy_poll.o \ + library/cipher.o \ + library/version_features.o \ + library/ripemd160.o \ + library/rsa.o \ + library/md.o \ + library/md_wrap.o \ + library/sha256.o \ + library/dhm.o \ + library/ssl_cache.o \ + library/pkwrite.o \ + library/base64.o \ + library/asn1parse.o \ + library/ssl_tls.o \ + library/hmac_drbg.o \ + library/pem.o \ + library/version.o \ + library/gcm.o \ + library/memory_buffer_alloc.o \ + library/md2.o \ + library/ecdsa.o \ + library/ssl_srv.o \ + library/x509_crt.o \ + library/ecdh.o \ + library/asn1write.o \ + library/md4.o \ + library/debug.o \ + library/x509_create.o \ + library/ecjpake.o \ + library/oid.o \ + library/md5.o \ + library/ssl_ciphersuites.o \ + library/sha512.o \ + library/xtea.o \ + library/aes.o \ + library/cipher_wrap.o \ + library/arc4.o \ + library/bignum.o \ + library/pkparse.o \ + library/padlock.o \ + library/threading.o \ + library/x509_crl.o \ + library/pkcs11.o \ + library/aesni.o \ + library/timing.o \ + library/certs.o \ + library/pkcs5.o \ + library/ssl_cookie.o \ + library/camellia.o \ + library/havege.o \ + library/des.o \ + library/x509write_csr.o \ + library/platform.o \ + library/ctr_drbg.o \ + library/x509write_crt.o \ + library/pk_wrap.o \ + port/esp_bignum.o \ + port/esp_hardware.o \ + port/esp_sha1.o \ + port/esp_sha256.o \ + port/esp_sha512.o \ + ) + +$(BUILD)/$(ESPCOMP)/wpa_supplicant/%.o: CFLAGS += -DEMBEDDED_SUPP -D__ets__ -Wno-strict-aliasing +ESPIDF_WPA_SUPPLICANT_O = $(addprefix $(ESPCOMP)/wpa_supplicant/,\ + src/crypto/aes-internal-enc.o \ + src/crypto/sha256-internal.o \ + src/crypto/md5-internal.o \ + src/crypto/aes-internal.o \ + src/crypto/sha1.o \ + src/crypto/aes-internal-dec.o \ + src/crypto/aes-unwrap.o \ + src/crypto/crypto_internal-rsa.o \ + src/crypto/dh_groups.o \ + src/crypto/crypto_internal.o \ + src/crypto/aes-wrap.o \ + src/crypto/sha1-internal.o \ + src/crypto/dh_group5.o \ + src/crypto/sha256.o \ + src/crypto/rc4.o \ + src/crypto/md5.o \ + src/crypto/aes-cbc.o \ + src/crypto/sha1-pbkdf2.o \ + src/crypto/bignum.o \ + src/crypto/crypto_internal-modexp.o \ + src/crypto/crypto_internal-cipher.o \ + src/fast_crypto/fast_aes-unwrap.o \ + src/fast_crypto/fast_aes-wrap.o \ + src/fast_crypto/fast_sha256.o \ + src/fast_crypto/fast_sha256-internal.o \ + port/os_xtensa.o \ + ) + +OBJ_ESPIDF = +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NEWLIB_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_DRIVER_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ESP32_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_HEAP_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SOC_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_CXX_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ETHERNET_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_EXPAT_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_PTHREAD_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_FREERTOS_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_VFS_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_JSON_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_LOG_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_LWIP_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_MBEDTLS_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_XTENSA_DEBUG_MODULE_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_TCPIP_ADAPTER_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_APP_TRACE_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NGHTTP_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NVS_FLASH_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_OPENSSL_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SPI_FLASH_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_WPA_SUPPLICANT_O)) +################################################################################ +# Main targets + +all: $(BUILD)/firmware.bin + +.PHONY: idf-version deploy erase + +idf-version: + $(ECHO) "ESP IDF supported hash: $(ESPIDF_SUPHASH)" + +$(BUILD)/firmware.bin: $(BUILD)/bootloader.bin $(BUILD)/partitions.bin $(BUILD)/application.bin + $(ECHO) "Create $@" + $(Q)$(PYTHON) makeimg.py $^ $@ + +deploy: $(BUILD)/firmware.bin + $(ECHO) "Writing $^ to the board" + $(Q)$(ESPTOOL) --chip esp32 --port $(PORT) --baud $(BAUD) write_flash -z --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) 0x1000 $^ + +erase: + $(ECHO) "Erasing flash" + $(Q)$(ESPTOOL) --chip esp32 --port $(PORT) --baud $(BAUD) erase_flash + +################################################################################ +# Declarations to build the application + +OBJ = $(OBJ_MP) $(OBJ_ESPIDF) + +APP_LD_ARGS = +APP_LD_ARGS += $(LDFLAGS_MOD) +APP_LD_ARGS += --start-group +APP_LD_ARGS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc +APP_LD_ARGS += -L$(dir $(LIBSTDCXX_FILE_NAME)) -lstdc++ +APP_LD_ARGS += $(ESPCOMP)/newlib/lib/libc.a +APP_LD_ARGS += $(ESPCOMP)/newlib/lib/libm.a +APP_LD_ARGS += $(ESPCOMP)/esp32/libhal.a +APP_LD_ARGS += -L$(ESPCOMP)/esp32/lib -lcore -lnet80211 -lphy -lrtc -lpp -lwpa -lsmartconfig -lcoexist +APP_LD_ARGS += $(OBJ) +APP_LD_ARGS += --end-group + +$(BUILD)/esp32_out.ld: sdkconfig.h + $(Q)$(CC) -I. -C -P -x c -E $(ESPCOMP)/esp32/ld/esp32.ld -o $@ + +$(BUILD)/application.bin: $(BUILD)/application.elf + $(ECHO) "Create $@" + $(Q)$(ESPTOOL) --chip esp32 elf2image --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) --flash_size $(FLASH_SIZE) $< + +$(BUILD)/application.elf: $(OBJ) $(BUILD)/esp32_out.ld + $(ECHO) "LINK $@" + $(Q)$(LD) $(LDFLAGS) -o $@ $(APP_LD_ARGS) + $(Q)$(SIZE) $@ + +define compile_cxx +$(ECHO) "CXX $<" +$(Q)$(CXX) $(CXXFLAGS) -c -MD -o $@ $< +@# The following fixes the dependency file. +@# See http://make.paulandlesley.org/autodep.html for details. +@# Regex adjusted from the above to play better with Windows paths, etc. +@$(CP) $(@:.o=.d) $(@:.o=.P); \ + $(SED) -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \ + $(RM) -f $(@:.o=.d) +endef + +vpath %.cpp . $(TOP) +$(BUILD)/%.o: %.cpp + $(call compile_cxx) + +################################################################################ +# Declarations to build the bootloader + +$(BUILD)/bootloader/$(ESPCOMP)/%.o: CFLAGS += -DBOOTLOADER_BUILD=1 -I$(ESPCOMP)/bootloader_support/include_priv -I$(ESPCOMP)/bootloader_support/include -I$(ESPCOMP)/micro-ecc/micro-ecc -I$(ESPCOMP)/esp32 -Wno-error=format +BOOTLOADER_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ + bootloader_support/src/bootloader_flash.o \ + bootloader_support/src/bootloader_random.o \ + bootloader_support/src/bootloader_sha.o \ + bootloader_support/src/secure_boot_signatures.o \ + bootloader_support/src/secure_boot.o \ + bootloader_support/src/esp_image_format.o \ + bootloader_support/src/flash_encrypt.o \ + bootloader_support/src/flash_partitions.o \ + log/log.o \ + spi_flash/spi_flash_rom_patch.o \ + soc/esp32/rtc_clk.o \ + soc/esp32/rtc_time.o \ + micro-ecc/micro-ecc/uECC.o \ + bootloader/subproject/main/bootloader_start.o \ + ) + +BOOTLOADER_LIBS = +BOOTLOADER_LIBS += -Wl,--start-group +BOOTLOADER_LIBS += $(BOOTLOADER_OBJ) +BOOTLOADER_LIBS += -L$(ESPCOMP)/esp32/lib -lrtc +BOOTLOADER_LIBS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc +BOOTLOADER_LIBS += -Wl,--end-group + +BOOTLOADER_LDFLAGS = +BOOTLOADER_LDFLAGS += -nostdlib +BOOTLOADER_LDFLAGS += -L$(ESPIDF)/lib +BOOTLOADER_LDFLAGS += -L$(ESPIDF)/ld +BOOTLOADER_LDFLAGS += -u call_user_start_cpu0 +BOOTLOADER_LDFLAGS += -Wl,--gc-sections +BOOTLOADER_LDFLAGS += -static +BOOTLOADER_LDFLAGS += -Wl,-EL +BOOTLOADER_LDFLAGS += -Wl,-Map=$(@:.elf=.map) -Wl,--cref +BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/bootloader/subproject/main/esp32.bootloader.ld +BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/bootloader/subproject/main/esp32.bootloader.rom.ld +BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.rom.ld +BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.rom.spiram_incompatible_fns.ld + +BOOTLOADER_OBJ_DIRS = $(sort $(dir $(BOOTLOADER_OBJ))) +$(BOOTLOADER_OBJ): | $(BOOTLOADER_OBJ_DIRS) +$(BOOTLOADER_OBJ_DIRS): + $(MKDIR) -p $@ + +$(BUILD)/bootloader/%.o: %.c + $(call compile_c) + +$(BUILD)/bootloader.bin: $(BUILD)/bootloader.elf + $(ECHO) "Create $@" + $(Q)$(ESPTOOL) --chip esp32 elf2image --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) --flash_size $(FLASH_SIZE) $< + +$(BUILD)/bootloader.elf: $(BOOTLOADER_OBJ) + $(ECHO) "LINK $@" + $(Q)$(CC) $(BOOTLOADER_LDFLAGS) -o $@ $(BOOTLOADER_LIBS) + +################################################################################ +# Declarations to build the partitions + +PYTHON2 ?= python2 +PART_SRC = $(ESPCOMP)/partition_table/partitions_singleapp.csv + +$(BUILD)/partitions.bin: $(PART_SRC) + $(ECHO) "Create $@" + $(Q)$(PYTHON2) $(ESPCOMP)/partition_table/gen_esp32part.py -q $< $@ + +################################################################################ + +include $(TOP)/py/mkrules.mk diff --git a/ports/esp32/README.md b/ports/esp32/README.md new file mode 100644 index 0000000000..7591f040a6 --- /dev/null +++ b/ports/esp32/README.md @@ -0,0 +1,199 @@ +MicroPython port to the ESP32 +============================= + +This is an experimental port of MicroPython to the Espressif ESP32 +microcontroller. It uses the ESP-IDF framework and MicroPython runs as +a task under FreeRTOS. + +Supported features include: +- REPL (Python prompt) over UART0. +- 16k stack for the MicroPython task and 64k Python heap. +- Many of MicroPython's features are enabled: unicode, arbitrary-precision + integers, single-precision floats, complex numbers, frozen bytecode, as + well as many of the internal modules. +- Internal filesystem using the flash (currently 256k in size). +- The machine module with basic GPIO and bit-banging I2C, SPI support. + +Development of this ESP32 port was sponsored in part by Microbric Pty Ltd. + +Setting up the toolchain and ESP-IDF +------------------------------------ + +There are two main components that are needed to build the firmware: +- the Xtensa cross-compiler that targets the CPU in the ESP32 (this is + different to the compiler used by the ESP8266) +- the Espressif IDF (IoT development framework, aka SDK) + +Instructions for setting up both of these components are provided by the +ESP-IDF itself, which is found at https://github.com/espressif/esp-idf . +Follow the guide "Setting Up ESP-IDF", for Windows, Mac or Linux. You +only need to perform up to "Step 2" of the guide, by which stage you +should have installed the cross-compile and cloned the ESP-IDF repository. + +If you are on a Windows machine then the +[Windows Subsystem for Linux](https://msdn.microsoft.com/en-au/commandline/wsl/install_guide) +is the most efficient way to install the ESP32 toolchain and build the project. +If you use WSL then follow the +[Linux guidelines](http://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html) +for the ESP-IDF instead of the Windows ones. + +Be advised that the ESP-IDF is still undergoing changes and only some +versions are supported. To find which build is compatible refer to the line +in the makefile containing the following: +``` +ESPIDF_SUPHASH := +``` +After finishing "Step 2" you can roll back your current build of +the ESP-IDF (and update the submodules accordingly) using: +``` +$ git checkout +$ git submodule update --recursive +``` +Note that you will get a warning when building the code if the ESP-IDF +version is incorrect. + +The Espressif ESP-IDF instructions above only install pyserial for Python 2, +so if you're running Python 3 or a non-system Python you'll also need to +install `pyserial` (or `esptool`) so that the Makefile can flash the board +and set parameters: +```bash +$ pip install pyserial +``` + +Once everything is set up you should have a functioning toolchain with +prefix xtensa-esp32-elf- (or otherwise if you configured it differently) +as well as a copy of the ESP-IDF repository. + +You then need to set the `ESPIDF` environment/makefile variable to point to +the root of the ESP-IDF repository. You can set the variable in your PATH, +or at the command line when calling make, or in your own custom `makefile`. +The last option is recommended as it allows you to easily configure other +variables for the build. In that case, create a new file in the esp32 +directory called `makefile` and add the following lines to that file: +``` +ESPIDF = +#PORT = /dev/ttyUSB0 +#FLASH_MODE = qio +#FLASH_SIZE = 4MB +#CROSS_COMPILE = xtensa-esp32-elf- + +include Makefile +``` +Be sure to enter the correct path to your local copy of the IDF repository +(and use `$(HOME)`, not tilde, to reference your home directory). +If your filesystem is case-insensitive then you'll need to use `GNUmakefile` +instead of `makefile`. +If the Xtensa cross-compiler is not in your path you can use the +`CROSS_COMPILE` variable to set its location. Other options of interest +are `PORT` for the serial port of your esp32 module, and `FLASH_MODE` +(which may need to be `dio` for some modules) +and `FLASH_SIZE`. See the Makefile for further information. + +Building the firmware +--------------------- + +The MicroPython cross-compiler must be built to pre-compile some of the +built-in scripts to bytecode. This can be done by (from the root of +this repository): +```bash +$ make -C mpy-cross +``` + +The ESP32 port has a dependency on Berkeley DB, which is an external +dependency (git submodule). You'll need to have git initialize that +module using the commands: +```bash +$ git submodule init lib/berkeley-db-1.xx +$ git submodule update +``` + +Then to build MicroPython for the ESP32 run: +```bash +$ cd ports/esp32 +$ make +``` +This will produce binary firmware images in the `build/` subdirectory +(three of them: bootloader.bin, partitions.bin and application.bin). + +To flash the firmware you must have your ESP32 module in the bootloader +mode and connected to a serial port on your PC. Refer to the documentation +for your particular ESP32 module for how to do this. The serial port and +flash settings are set in the `Makefile`, and can be overridden in your +local `makefile`; see above for more details. + +You will also need to have user permissions to access the /dev/ttyUSB0 device. +On Linux, you can enable this by adding your user to the `dialout` group, +and rebooting or logging out and in again. +```bash +$ sudo adduser dialout +``` + +If you are installing MicroPython to your module for the first time, or +after installing any other firmware, you should first erase the flash +completely: +```bash +$ make erase +``` + +To flash the MicroPython firmware to your ESP32 use: +```bash +$ make deploy +``` +This will use the `esptool.py` script (provided by ESP-IDF) to download the +binary images. + +Getting a Python prompt +----------------------- + +You can get a prompt via the serial port, via UART0, which is the same UART +that is used for programming the firmware. The baudrate for the REPL is +115200 and you can use a command such as: +```bash +$ picocom -b 115200 /dev/ttyUSB0 +``` + +Configuring the WiFi and using the board +---------------------------------------- + +The ESP32 port is designed to be (almost) equivalent to the ESP8266 in +terms of the modules and user-facing API. There are some small differences, +notably that the ESP32 does not automatically connect to the last access +point when booting up. But for the most part the documentation and tutorials +for the ESP8266 should apply to the ESP32 (at least for the components that +are implemented). + +See http://docs.micropython.org/en/latest/esp8266/esp8266/quickref.html for +a quick reference, and http://docs.micropython.org/en/latest/esp8266/esp8266/tutorial/intro.html +for a tutorial. + +The following function can be used to connect to a WiFi access point (you can +either pass in your own SSID and password, or change the defaults so you can +quickly call `wlan_connect()` and it just works): +```python +def wlan_connect(ssid='MYSSID', password='MYPASS'): + import network + wlan = network.WLAN(network.STA_IF) + if not wlan.active() or not wlan.isconnected(): + wlan.active(True) + print('connecting to:', ssid) + wlan.connect(ssid, password) + while not wlan.isconnected(): + pass + print('network config:', wlan.ifconfig()) +``` + +Note that some boards require you to configure the WiFi antenna before using +the WiFi. On Pycom boards like the LoPy and WiPy 2.0 you need to execute the +following code to select the internal antenna (best to put this line in your +boot.py file): +```python +import machine +antenna = machine.Pin(16, machine.Pin.OUT, value=0) +``` + +Troubleshooting +--------------- + +* Continuous reboots after programming: Ensure FLASH_MODE is correct for your + board (e.g. ESP-WROOM-32 should be DIO). Then perform a `make clean`, rebuild, + redeploy. diff --git a/ports/esp32/esp32.custom_common.ld b/ports/esp32/esp32.custom_common.ld new file mode 100644 index 0000000000..45242f9af2 --- /dev/null +++ b/ports/esp32/esp32.custom_common.ld @@ -0,0 +1,215 @@ +/* Default entry point: */ +ENTRY(call_start_cpu0); + +SECTIONS +{ + /* RTC fast memory holds RTC wake stub code, + including from any source file named rtc_wake_stub*.c + */ + .rtc.text : + { + . = ALIGN(4); + *(.rtc.literal .rtc.text) + *rtc_wake_stub*.o(.literal .text .literal.* .text.*) + } >rtc_iram_seg + + /* RTC slow memory holds RTC wake stub + data/rodata, including from any source file + named rtc_wake_stub*.c + */ + .rtc.data : + { + _rtc_data_start = ABSOLUTE(.); + *(.rtc.data) + *(.rtc.rodata) + *rtc_wake_stub*.o(.data .rodata .data.* .rodata.* .bss .bss.*) + _rtc_data_end = ABSOLUTE(.); + } > rtc_slow_seg + + /* RTC bss, from any source file named rtc_wake_stub*.c */ + .rtc.bss (NOLOAD) : + { + _rtc_bss_start = ABSOLUTE(.); + *rtc_wake_stub*.o(.bss .bss.*) + *rtc_wake_stub*.o(COMMON) + _rtc_bss_end = ABSOLUTE(.); + } > rtc_slow_seg + + /* Send .iram0 code to iram */ + .iram0.vectors : + { + /* Vectors go to IRAM */ + _init_start = ABSOLUTE(.); + /* Vectors according to builds/RF-2015.2-win32/esp108_v1_2_s5_512int_2/config.html */ + . = 0x0; + KEEP(*(.WindowVectors.text)); + . = 0x180; + KEEP(*(.Level2InterruptVector.text)); + . = 0x1c0; + KEEP(*(.Level3InterruptVector.text)); + . = 0x200; + KEEP(*(.Level4InterruptVector.text)); + . = 0x240; + KEEP(*(.Level5InterruptVector.text)); + . = 0x280; + KEEP(*(.DebugExceptionVector.text)); + . = 0x2c0; + KEEP(*(.NMIExceptionVector.text)); + . = 0x300; + KEEP(*(.KernelExceptionVector.text)); + . = 0x340; + KEEP(*(.UserExceptionVector.text)); + . = 0x3C0; + KEEP(*(.DoubleExceptionVector.text)); + . = 0x400; + *(.*Vector.literal) + + *(.UserEnter.literal); + *(.UserEnter.text); + . = ALIGN (16); + *(.entry.text) + *(.init.literal) + *(.init) + _init_end = ABSOLUTE(.); + + /* This goes here, not at top of linker script, so addr2line finds it last, + and uses it in preference to the first symbol in IRAM */ + _iram_start = ABSOLUTE(0); + } > iram0_0_seg + + .iram0.text : + { + /* Code marked as runnning out of IRAM */ + _iram_text_start = ABSOLUTE(.); + *(.iram1 .iram1.*) + *freertos/*(.literal .text .literal.* .text.*) + *heap/multi_heap.o(.literal .text .literal.* .text.*) + *heap/multi_heap_poisoning.o(.literal .text .literal.* .text.*) + *esp32/panic.o(.literal .text .literal.* .text.*) + *esp32/core_dump.o(.literal .text .literal.* .text.*) + *app_trace/*(.literal .text .literal.* .text.*) + *xtensa-debug-module/eri.o(.literal .text .literal.* .text.*) + *esp32/app_trace.o(.literal .text .literal.* .text.*) + *libphy.a:(.literal .text .literal.* .text.*) + *librtc.a:(.literal .text .literal.* .text.*) + *libsoc.a:(.literal .text .literal.* .text.*) + *libhal.a:(.literal .text .literal.* .text.*) + *libgcc.a:lib2funcs.o(.literal .text .literal.* .text.*) + *spi_flash/spi_flash_rom_patch.o(.literal .text .literal.* .text.*) + *py/scheduler.o*(.literal .text .literal.* .text.*) + _iram_text_end = ABSOLUTE(.); + } > iram0_0_seg + + .dram0.data : + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + *(.dram1 .dram1.*) + *esp32/panic.o(.rodata .rodata.*) + *libphy.a:(.rodata .rodata.*) + *app_trace/app_trace.o:(.rodata .rodata.*) + *heap/multi_heap.o(.rodata .rodata.*) + *heap/multi_heap_poisoning.o(.rodata .rodata.*) + _data_end = ABSOLUTE(.); + . = ALIGN(4); + } >dram0_0_seg + + /* Shared RAM */ + .dram0.bss (NOLOAD) : + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.share.mem) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + _heap_start = ABSOLUTE(.); + } >dram0_0_seg + + .flash.rodata : + { + _rodata_start = ABSOLUTE(.); + *(.rodata) + *(.rodata.*) + *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE_ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table .gcc_except_table.*) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + . = (. + 3) & ~ 3; + __eh_frame = ABSOLUTE(.); + KEEP(*(.eh_frame)) + . = (. + 7) & ~ 3; + /* C++ constructor and destructor tables, properly ordered: */ + __init_array_start = ABSOLUTE(.); + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + __init_array_end = ABSOLUTE(.); + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS_ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + _rodata_end = ABSOLUTE(.); + /* Literals are also RO data. */ + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + . = ALIGN(4); + } >drom0_0_seg + + .flash.text : + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.irom0.text) /* catch stray ICACHE_RODATA_ATTR */ + *(.fini.literal) + *(.fini) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + + /* Similar to _iram_start, this symbol goes here so it is + resolved by addr2line in preference to the first symbol in + the flash.text segment. + */ + _flash_cache_start = ABSOLUTE(0); + } >iram0_2_seg +} diff --git a/ports/esp32/espneopixel.c b/ports/esp32/espneopixel.c new file mode 100644 index 0000000000..829c8b1c80 --- /dev/null +++ b/ports/esp32/espneopixel.c @@ -0,0 +1,53 @@ +// Original version from https://github.com/adafruit/Adafruit_NeoPixel +// Modifications by dpgeorge to support auto-CPU-frequency detection + +// This is a mash-up of the Due show() code + insights from Michael Miller's +// ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus +// Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution. + +#include "py/mpconfig.h" +#include "py/mphal.h" +#include "modesp.h" + +void IRAM_ATTR esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t timing) { + uint8_t *p, *end, pix, mask; + uint32_t t, time0, time1, period, c, startTime, pinMask; + + pinMask = 1 << pin; + p = pixels; + end = p + numBytes; + pix = *p++; + mask = 0x80; + startTime = 0; + + uint32_t fcpu = ets_get_cpu_frequency() * 1000000; + + if (timing == 1) { + // 800 KHz + time0 = (fcpu * 0.35) / 1000000; // 0.35us + time1 = (fcpu * 0.8) / 1000000; // 0.8us + period = (fcpu * 1.25) / 1000000; // 1.25us per bit + } else { + // 400 KHz + time0 = (fcpu * 0.5) / 1000000; // 0.35us + time1 = (fcpu * 1.2) / 1000000; // 0.8us + period = (fcpu * 2.5) / 1000000; // 1.25us per bit + } + + uint32_t irq_state = mp_hal_quiet_timing_enter(); + for (t = time0;; t = time0) { + if (pix & mask) t = time1; // Bit high duration + while (((c = mp_hal_ticks_cpu()) - startTime) < period); // Wait for bit start + GPIO_REG_WRITE(GPIO_OUT_W1TS_REG, pinMask); // Set high + startTime = c; // Save start time + while (((c = mp_hal_ticks_cpu()) - startTime) < t); // Wait high duration + GPIO_REG_WRITE(GPIO_OUT_W1TC_REG, pinMask); // Set low + if (!(mask >>= 1)) { // Next bit/byte + if(p >= end) break; + pix = *p++; + mask = 0x80; + } + } + while ((mp_hal_ticks_cpu() - startTime) < period); // Wait for last bit + mp_hal_quiet_timing_exit(irq_state); +} diff --git a/ports/esp32/esponewire.c b/ports/esp32/esponewire.c new file mode 100644 index 0000000000..781616cbe4 --- /dev/null +++ b/ports/esp32/esponewire.c @@ -0,0 +1,80 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mphal.h" +#include "esp8266/esponewire.h" + +#define TIMING_RESET1 (0) +#define TIMING_RESET2 (1) +#define TIMING_RESET3 (2) +#define TIMING_READ1 (3) +#define TIMING_READ2 (4) +#define TIMING_READ3 (5) +#define TIMING_WRITE1 (6) +#define TIMING_WRITE2 (7) +#define TIMING_WRITE3 (8) + +uint16_t esp_onewire_timings[9] = {480, 40, 420, 5, 5, 40, 10, 50, 10}; + +#define DELAY_US mp_hal_delay_us_fast + +int esp_onewire_reset(mp_hal_pin_obj_t pin) { + mp_hal_pin_write(pin, 0); + DELAY_US(esp_onewire_timings[TIMING_RESET1]); + uint32_t i = MICROPY_BEGIN_ATOMIC_SECTION(); + mp_hal_pin_write(pin, 1); + DELAY_US(esp_onewire_timings[TIMING_RESET2]); + int status = !mp_hal_pin_read(pin); + MICROPY_END_ATOMIC_SECTION(i); + DELAY_US(esp_onewire_timings[TIMING_RESET3]); + return status; +} + +int esp_onewire_readbit(mp_hal_pin_obj_t pin) { + mp_hal_pin_write(pin, 1); + uint32_t i = MICROPY_BEGIN_ATOMIC_SECTION(); + mp_hal_pin_write(pin, 0); + DELAY_US(esp_onewire_timings[TIMING_READ1]); + mp_hal_pin_write(pin, 1); + DELAY_US(esp_onewire_timings[TIMING_READ2]); + int value = mp_hal_pin_read(pin); + MICROPY_END_ATOMIC_SECTION(i); + DELAY_US(esp_onewire_timings[TIMING_READ3]); + return value; +} + +void esp_onewire_writebit(mp_hal_pin_obj_t pin, int value) { + uint32_t i = MICROPY_BEGIN_ATOMIC_SECTION(); + mp_hal_pin_write(pin, 0); + DELAY_US(esp_onewire_timings[TIMING_WRITE1]); + if (value) { + mp_hal_pin_write(pin, 1); + } + DELAY_US(esp_onewire_timings[TIMING_WRITE2]); + mp_hal_pin_write(pin, 1); + DELAY_US(esp_onewire_timings[TIMING_WRITE3]); + MICROPY_END_ATOMIC_SECTION(i); +} diff --git a/ports/esp32/fatfs_port.c b/ports/esp32/fatfs_port.c new file mode 100644 index 0000000000..b3690a01fb --- /dev/null +++ b/ports/esp32/fatfs_port.c @@ -0,0 +1,46 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014, 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "lib/oofatfs/ff.h" +#include "timeutils.h" +//#include "modmachine.h" + +DWORD get_fattime(void) { + + // TODO: Optimize division (there's no HW division support on ESP8266, + // so it's expensive). + //uint32_t secs = (uint32_t)(pyb_rtc_get_us_since_2000() / 1000000); + uint32_t secs = 0; + + timeutils_struct_time_t tm; + timeutils_seconds_since_2000_to_struct_time(secs, &tm); + + return (((DWORD)(tm.tm_year - 1980) << 25) | ((DWORD)tm.tm_mon << 21) | ((DWORD)tm.tm_mday << 16) | + ((DWORD)tm.tm_hour << 11) | ((DWORD)tm.tm_min << 5) | ((DWORD)tm.tm_sec >> 1)); +} diff --git a/ports/esp32/gccollect.c b/ports/esp32/gccollect.c new file mode 100644 index 0000000000..9843cef008 --- /dev/null +++ b/ports/esp32/gccollect.c @@ -0,0 +1,66 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * Copyright (c) 2017 Pycom Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/mpconfig.h" +#include "py/mpstate.h" +#include "py/gc.h" +#include "py/mpthread.h" +#include "gccollect.h" +#include "soc/cpu.h" +#include "xtensa/hal.h" + + +static void gc_collect_inner(int level) { + if (level < XCHAL_NUM_AREGS / 8) { + gc_collect_inner(level + 1); + if (level != 0) { + return; + } + } + + if (level == XCHAL_NUM_AREGS / 8) { + // get the sp + volatile uint32_t sp = (uint32_t)get_sp(); + gc_collect_root((void**)sp, ((mp_uint_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t)); + return; + } + + // trace root pointers from any threads + #if MICROPY_PY_THREAD + mp_thread_gc_others(); + #endif +} + +void gc_collect(void) { + gc_collect_start(); + gc_collect_inner(0); + gc_collect_end(); +} diff --git a/ports/esp32/gccollect.h b/ports/esp32/gccollect.h new file mode 100644 index 0000000000..fe02cc62be --- /dev/null +++ b/ports/esp32/gccollect.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +extern uint32_t _text_start; +extern uint32_t _text_end; +extern uint32_t _irom0_text_start; +extern uint32_t _irom0_text_end; +extern uint32_t _data_start; +extern uint32_t _data_end; +extern uint32_t _rodata_start; +extern uint32_t _rodata_end; +extern uint32_t _bss_start; +extern uint32_t _bss_end; +extern uint32_t _heap_start; +extern uint32_t _heap_end; + +void gc_collect(void); diff --git a/ports/esp32/help.c b/ports/esp32/help.c new file mode 100644 index 0000000000..95d115c563 --- /dev/null +++ b/ports/esp32/help.c @@ -0,0 +1,65 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/builtin.h" + +const char esp32_help_text[] = +"Welcome to MicroPython on the ESP32!\n" +"\n" +"For generic online docs please visit http://docs.micropython.org/\n" +"\n" +"For access to the hardware use the 'machine' module:\n" +"\n" +"import machine\n" +"pin12 = machine.Pin(12, machine.Pin.OUT)\n" +"pin12.value(1)\n" +"pin13 = machine.Pin(13, machine.Pin.IN, machine.Pin.PULL_UP)\n" +"print(pin13.value())\n" +"i2c = machine.I2C(scl=machine.Pin(21), sda=machine.Pin(22))\n" +"i2c.scan()\n" +"i2c.writeto(addr, b'1234')\n" +"i2c.readfrom(addr, 4)\n" +"\n" +"Basic WiFi configuration:\n" +"\n" +"import network\n" +"sta_if = network.WLAN(network.STA_IF); sta_if.active(True)\n" +"sta_if.scan() # Scan for available access points\n" +"sta_if.connect(\"\", \"\") # Connect to an AP\n" +"sta_if.isconnected() # Check for successful connection\n" +"\n" +"Control commands:\n" +" CTRL-A -- on a blank line, enter raw REPL mode\n" +" CTRL-B -- on a blank line, enter normal REPL mode\n" +" CTRL-C -- interrupt a running program\n" +" CTRL-D -- on a blank line, do a soft reset of the board\n" +" CTRL-E -- on a blank line, enter paste mode\n" +"\n" +"For further help on a specific object, type help(obj)\n" +"For a list of available modules, type help('modules')\n" +; diff --git a/ports/esp32/machine_adc.c b/ports/esp32/machine_adc.c new file mode 100644 index 0000000000..d62f362e96 --- /dev/null +++ b/ports/esp32/machine_adc.c @@ -0,0 +1,132 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Nick Moore + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include + +#include "esp_log.h" + +#include "driver/gpio.h" +#include "driver/adc.h" + +#include "py/runtime.h" +#include "py/mphal.h" +#include "modmachine.h" + +typedef struct _madc_obj_t { + mp_obj_base_t base; + gpio_num_t gpio_id; + adc1_channel_t adc1_id; +} madc_obj_t; + +STATIC const madc_obj_t madc_obj[] = { + {{&machine_adc_type}, GPIO_NUM_36, ADC1_CHANNEL_0}, + {{&machine_adc_type}, GPIO_NUM_37, ADC1_CHANNEL_1}, + {{&machine_adc_type}, GPIO_NUM_38, ADC1_CHANNEL_2}, + {{&machine_adc_type}, GPIO_NUM_39, ADC1_CHANNEL_3}, + {{&machine_adc_type}, GPIO_NUM_32, ADC1_CHANNEL_4}, + {{&machine_adc_type}, GPIO_NUM_33, ADC1_CHANNEL_5}, + {{&machine_adc_type}, GPIO_NUM_34, ADC1_CHANNEL_6}, + {{&machine_adc_type}, GPIO_NUM_35, ADC1_CHANNEL_7}, +}; + +STATIC mp_obj_t madc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, + const mp_obj_t *args) { + + static int initialized = 0; + if (!initialized) { + adc1_config_width(ADC_WIDTH_12Bit); + initialized = 1; + } + + mp_arg_check_num(n_args, n_kw, 1, 1, true); + gpio_num_t pin_id = machine_pin_get_id(args[0]); + const madc_obj_t *self = NULL; + for (int i = 0; i < MP_ARRAY_SIZE(madc_obj); i++) { + if (pin_id == madc_obj[i].gpio_id) { self = &madc_obj[i]; break; } + } + if (!self) mp_raise_ValueError("invalid Pin for ADC"); + esp_err_t err = adc1_config_channel_atten(self->adc1_id, ADC_ATTEN_0db); + if (err == ESP_OK) return MP_OBJ_FROM_PTR(self); + mp_raise_ValueError("Parameter Error"); +} + +STATIC void madc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + madc_obj_t *self = self_in; + mp_printf(print, "ADC(Pin(%u))", self->gpio_id); +} + +STATIC mp_obj_t madc_read(mp_obj_t self_in) { + madc_obj_t *self = self_in; + int val = adc1_get_raw(self->adc1_id); + if (val == -1) mp_raise_ValueError("Parameter Error"); + return MP_OBJ_NEW_SMALL_INT(val); +} +MP_DEFINE_CONST_FUN_OBJ_1(madc_read_obj, madc_read); + +STATIC mp_obj_t madc_atten(mp_obj_t self_in, mp_obj_t atten_in) { + madc_obj_t *self = self_in; + adc_atten_t atten = mp_obj_get_int(atten_in); + esp_err_t err = adc1_config_channel_atten(self->adc1_id, atten); + if (err == ESP_OK) return mp_const_none; + mp_raise_ValueError("Parameter Error"); +} +MP_DEFINE_CONST_FUN_OBJ_2(madc_atten_obj, madc_atten); + +STATIC mp_obj_t madc_width(mp_obj_t cls_in, mp_obj_t width_in) { + adc_bits_width_t width = mp_obj_get_int(width_in); + esp_err_t err = adc1_config_width(width); + if (err == ESP_OK) return mp_const_none; + mp_raise_ValueError("Parameter Error"); +} +MP_DEFINE_CONST_FUN_OBJ_2(madc_width_fun_obj, madc_width); +MP_DEFINE_CONST_CLASSMETHOD_OBJ(madc_width_obj, MP_ROM_PTR(&madc_width_fun_obj)); + +STATIC const mp_rom_map_elem_t madc_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&madc_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_atten), MP_ROM_PTR(&madc_atten_obj) }, + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&madc_width_obj) }, + + { MP_ROM_QSTR(MP_QSTR_ATTN_0DB), MP_ROM_INT(ADC_ATTEN_0db) }, + { MP_ROM_QSTR(MP_QSTR_ATTN_2_5DB), MP_ROM_INT(ADC_ATTEN_2_5db) }, + { MP_ROM_QSTR(MP_QSTR_ATTN_6DB), MP_ROM_INT(ADC_ATTEN_6db) }, + { MP_ROM_QSTR(MP_QSTR_ATTN_11DB), MP_ROM_INT(ADC_ATTEN_11db) }, + + { MP_ROM_QSTR(MP_QSTR_WIDTH_9BIT), MP_ROM_INT(ADC_WIDTH_9Bit) }, + { MP_ROM_QSTR(MP_QSTR_WIDTH_10BIT), MP_ROM_INT(ADC_WIDTH_10Bit) }, + { MP_ROM_QSTR(MP_QSTR_WIDTH_11BIT), MP_ROM_INT(ADC_WIDTH_11Bit) }, + { MP_ROM_QSTR(MP_QSTR_WIDTH_12BIT), MP_ROM_INT(ADC_WIDTH_12Bit) }, +}; + +STATIC MP_DEFINE_CONST_DICT(madc_locals_dict, madc_locals_dict_table); + +const mp_obj_type_t machine_adc_type = { + { &mp_type_type }, + .name = MP_QSTR_ADC, + .print = madc_print, + .make_new = madc_make_new, + .locals_dict = (mp_obj_t)&madc_locals_dict, +}; diff --git a/ports/esp32/machine_dac.c b/ports/esp32/machine_dac.c new file mode 100644 index 0000000000..bd0804ec41 --- /dev/null +++ b/ports/esp32/machine_dac.c @@ -0,0 +1,97 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Nick Moore + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include + +#include "esp_log.h" + +#include "driver/gpio.h" +#include "driver/dac.h" + +#include "py/runtime.h" +#include "py/mphal.h" +#include "modmachine.h" + +typedef struct _mdac_obj_t { + mp_obj_base_t base; + gpio_num_t gpio_id; + dac_channel_t dac_id; +} mdac_obj_t; + +STATIC const mdac_obj_t mdac_obj[] = { + {{&machine_dac_type}, GPIO_NUM_25, DAC_CHANNEL_1}, + {{&machine_dac_type}, GPIO_NUM_26, DAC_CHANNEL_2}, +}; + +STATIC mp_obj_t mdac_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, + const mp_obj_t *args) { + + mp_arg_check_num(n_args, n_kw, 1, 1, true); + gpio_num_t pin_id = machine_pin_get_id(args[0]); + const mdac_obj_t *self = NULL; + for (int i = 0; i < MP_ARRAY_SIZE(mdac_obj); i++) { + if (pin_id == mdac_obj[i].gpio_id) { self = &mdac_obj[i]; break; } + } + if (!self) mp_raise_ValueError("invalid Pin for DAC"); + + esp_err_t err = dac_output_enable(self->dac_id); + if (err == ESP_OK) { + err = dac_output_voltage(self->dac_id, 0); + } + if (err == ESP_OK) return MP_OBJ_FROM_PTR(self); + mp_raise_ValueError("Parameter Error"); +} + +STATIC void mdac_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + mdac_obj_t *self = self_in; + mp_printf(print, "DAC(Pin(%u))", self->gpio_id); +} + +STATIC mp_obj_t mdac_write(mp_obj_t self_in, mp_obj_t value_in) { + mdac_obj_t *self = self_in; + int value = mp_obj_get_int(value_in); + if (value < 0 || value > 255) mp_raise_ValueError("Value out of range"); + + esp_err_t err = dac_output_voltage(self->dac_id, value); + if (err == ESP_OK) return mp_const_none; + mp_raise_ValueError("Parameter Error"); +} +MP_DEFINE_CONST_FUN_OBJ_2(mdac_write_obj, mdac_write); + +STATIC const mp_rom_map_elem_t mdac_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mdac_write_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mdac_locals_dict, mdac_locals_dict_table); + +const mp_obj_type_t machine_dac_type = { + { &mp_type_type }, + .name = MP_QSTR_DAC, + .print = mdac_print, + .make_new = mdac_make_new, + .locals_dict = (mp_obj_t)&mdac_locals_dict, +}; diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c new file mode 100644 index 0000000000..437b620f5e --- /dev/null +++ b/ports/esp32/machine_hw_spi.c @@ -0,0 +1,370 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mphal.h" +#include "extmod/machine_spi.h" +#include "modmachine.h" + +#include "driver/spi_master.h" + +typedef struct _machine_hw_spi_obj_t { + mp_obj_base_t base; + spi_host_device_t host; + uint32_t baudrate; + uint8_t polarity; + uint8_t phase; + uint8_t bits; + uint8_t firstbit; + int8_t sck; + int8_t mosi; + int8_t miso; + spi_device_handle_t spi; + enum { + MACHINE_HW_SPI_STATE_NONE, + MACHINE_HW_SPI_STATE_INIT, + MACHINE_HW_SPI_STATE_DEINIT + } state; +} machine_hw_spi_obj_t; + +STATIC void machine_hw_spi_deinit_internal(machine_hw_spi_obj_t *self) { + switch (spi_bus_remove_device(self->spi)) { + case ESP_ERR_INVALID_ARG: + mp_raise_msg(&mp_type_OSError, "invalid configuration"); + return; + + case ESP_ERR_INVALID_STATE: + mp_raise_msg(&mp_type_OSError, "SPI device already freed"); + return; + } + + switch (spi_bus_free(self->host)) { + case ESP_ERR_INVALID_ARG: + mp_raise_msg(&mp_type_OSError, "invalid configuration"); + return; + + case ESP_ERR_INVALID_STATE: + mp_raise_msg(&mp_type_OSError, "SPI bus already freed"); + return; + } + + int8_t pins[3] = {self->miso, self->mosi, self->sck}; + + for (int i = 0; i < 3; i++) { + if (pins[i] != -1) { + gpio_pad_select_gpio(pins[i]); + gpio_matrix_out(pins[i], SIG_GPIO_OUT_IDX, false, false); + gpio_set_direction(pins[i], GPIO_MODE_INPUT); + } + } +} + +STATIC void machine_hw_spi_init_internal( + machine_hw_spi_obj_t *self, + int8_t host, + int32_t baudrate, + int8_t polarity, + int8_t phase, + int8_t bits, + int8_t firstbit, + int8_t sck, + int8_t mosi, + int8_t miso) { + + // if we're not initialized, then we're + // implicitly 'changed', since this is the init routine + bool changed = self->state != MACHINE_HW_SPI_STATE_INIT; + + esp_err_t ret; + + machine_hw_spi_obj_t old_self = *self; + + if (host != -1 && host != self->host) { + self->host = host; + changed = true; + } + + if (baudrate != -1 && baudrate != self->baudrate) { + self->baudrate = baudrate; + changed = true; + } + + if (polarity != -1 && polarity != self->polarity) { + self->polarity = polarity; + changed = true; + } + + if (phase != -1 && phase != self->phase) { + self->phase = phase; + changed = true; + } + + if (bits != -1 && bits != self->bits) { + self->bits = bits; + changed = true; + } + + if (firstbit != -1 && firstbit != self->firstbit) { + self->firstbit = firstbit; + changed = true; + } + + if (sck != -2 && sck != self->sck) { + self->sck = sck; + changed = true; + } + + if (mosi != -2 && mosi != self->mosi) { + self->mosi = mosi; + changed = true; + } + + if (miso != -2 && miso != self->miso) { + self->miso = miso; + changed = true; + } + + if (self->host != HSPI_HOST && self->host != VSPI_HOST) { + mp_raise_ValueError("SPI ID must be either HSPI(1) or VSPI(2)"); + } + + if (changed) { + if (self->state == MACHINE_HW_SPI_STATE_INIT) { + self->state = MACHINE_HW_SPI_STATE_DEINIT; + machine_hw_spi_deinit_internal(&old_self); + } + } else { + return; // no changes + } + + spi_bus_config_t buscfg = { + .miso_io_num = self->miso, + .mosi_io_num = self->mosi, + .sclk_io_num = self->sck, + .quadwp_io_num = -1, + .quadhd_io_num = -1 + }; + + spi_device_interface_config_t devcfg = { + .clock_speed_hz = self->baudrate, + .mode = self->phase | (self->polarity << 1), + .spics_io_num = -1, // No CS pin + .queue_size = 1, + .flags = self->firstbit == MICROPY_PY_MACHINE_SPI_LSB ? SPI_DEVICE_TXBIT_LSBFIRST | SPI_DEVICE_RXBIT_LSBFIRST : 0, + .pre_cb = NULL + }; + + //Initialize the SPI bus + // FIXME: Does the DMA matter? There are two + + ret = spi_bus_initialize(self->host, &buscfg, 1); + switch (ret) { + case ESP_ERR_INVALID_ARG: + mp_raise_msg(&mp_type_OSError, "invalid configuration"); + return; + + case ESP_ERR_INVALID_STATE: + mp_raise_msg(&mp_type_OSError, "SPI device already in use"); + return; + } + + ret = spi_bus_add_device(self->host, &devcfg, &self->spi); + switch (ret) { + case ESP_ERR_INVALID_ARG: + mp_raise_msg(&mp_type_OSError, "invalid configuration"); + spi_bus_free(self->host); + return; + + case ESP_ERR_NO_MEM: + mp_raise_msg(&mp_type_OSError, "out of memory"); + spi_bus_free(self->host); + return; + + case ESP_ERR_NOT_FOUND: + mp_raise_msg(&mp_type_OSError, "no free slots"); + spi_bus_free(self->host); + return; + } + self->state = MACHINE_HW_SPI_STATE_INIT; +} + +STATIC void machine_hw_spi_deinit(mp_obj_base_t *self_in) { + machine_hw_spi_obj_t *self = (machine_hw_spi_obj_t *) self_in; + if (self->state == MACHINE_HW_SPI_STATE_INIT) { + self->state = MACHINE_HW_SPI_STATE_DEINIT; + machine_hw_spi_deinit_internal(self); + } +} + +STATIC void machine_hw_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { + machine_hw_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + + int bits_to_send = len * self->bits; + bool shortMsg = len <= 4; + + if (self->state == MACHINE_HW_SPI_STATE_DEINIT) { + mp_raise_msg(&mp_type_OSError, "transfer on deinitialized SPI"); + return; + } + + struct spi_transaction_t transaction = { + .flags = 0, + .length = bits_to_send, + .tx_buffer = NULL, + .rx_buffer = NULL, + }; + + if (shortMsg) { + if (src != NULL) { + memcpy(&transaction.tx_data, src, len); + } + transaction.flags |= (SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA); + } else { + transaction.tx_buffer = src; + transaction.rx_buffer = dest; + } + + spi_device_transmit(self->spi, &transaction); + + if (shortMsg && dest != NULL) { + memcpy(dest, &transaction.rx_data, len); + } +} + +/******************************************************************************/ +// MicroPython bindings for hw_spi + +STATIC void machine_hw_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_hw_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "SPI(id=%u, baudrate=%u, polarity=%u, phase=%u, bits=%u, firstbit=%u, sck=%d, mosi=%d, miso=%d)", + self->host, self->baudrate, self->polarity, + self->phase, self->bits, self->firstbit, + self->sck, self->mosi, self->miso); +} + +STATIC void machine_hw_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + machine_hw_spi_obj_t *self = (machine_hw_spi_obj_t *) self_in; + + enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_INT , {.u_int = -1} }, + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), + allowed_args, args); + int8_t sck, mosi, miso; + + if (args[ARG_sck].u_obj == MP_OBJ_NULL) { + sck = -2; + } else if (args[ARG_sck].u_obj == mp_const_none) { + sck = -1; + } else { + sck = machine_pin_get_id(args[ARG_sck].u_obj); + } + + if (args[ARG_miso].u_obj == MP_OBJ_NULL) { + miso = -2; + } else if (args[ARG_miso].u_obj == mp_const_none) { + miso = -1; + } else { + miso = machine_pin_get_id(args[ARG_miso].u_obj); + } + + if (args[ARG_mosi].u_obj == MP_OBJ_NULL) { + mosi = -2; + } else if (args[ARG_mosi].u_obj == mp_const_none) { + mosi = -1; + } else { + mosi = machine_pin_get_id(args[ARG_mosi].u_obj); + } + + machine_hw_spi_init_internal(self, args[ARG_id].u_int, args[ARG_baudrate].u_int, + args[ARG_polarity].u_int, args[ARG_phase].u_int, args[ARG_bits].u_int, + args[ARG_firstbit].u_int, sck, mosi, miso); +} + +mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT , {.u_int = -1} }, + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 500000} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_PY_MACHINE_SPI_MSB} }, + { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + machine_hw_spi_obj_t *self = m_new_obj(machine_hw_spi_obj_t); + self->base.type = &machine_hw_spi_type; + + machine_hw_spi_init_internal( + self, + args[ARG_id].u_int, + args[ARG_baudrate].u_int, + args[ARG_polarity].u_int, + args[ARG_phase].u_int, + args[ARG_bits].u_int, + args[ARG_firstbit].u_int, + args[ARG_sck].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_sck].u_obj), + args[ARG_mosi].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_mosi].u_obj), + args[ARG_miso].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_miso].u_obj)); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC const mp_machine_spi_p_t machine_hw_spi_p = { + .init = machine_hw_spi_init, + .deinit = machine_hw_spi_deinit, + .transfer = machine_hw_spi_transfer, +}; + +const mp_obj_type_t machine_hw_spi_type = { + { &mp_type_type }, + .name = MP_QSTR_SPI, + .print = machine_hw_spi_print, + .make_new = machine_hw_spi_make_new, + .protocol = &machine_hw_spi_p, + .locals_dict = (mp_obj_dict_t *) &mp_machine_spi_locals_dict, +}; diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c new file mode 100644 index 0000000000..493dff3f50 --- /dev/null +++ b/ports/esp32/machine_pin.c @@ -0,0 +1,375 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "driver/gpio.h" + +#include "py/runtime.h" +#include "py/mphal.h" +#include "modmachine.h" +#include "extmod/virtpin.h" + +typedef struct _machine_pin_obj_t { + mp_obj_base_t base; + gpio_num_t id; +} machine_pin_obj_t; + +typedef struct _machine_pin_irq_obj_t { + mp_obj_base_t base; + gpio_num_t id; +} machine_pin_irq_obj_t; + +STATIC const machine_pin_obj_t machine_pin_obj[] = { + {{&machine_pin_type}, GPIO_NUM_0}, + {{&machine_pin_type}, GPIO_NUM_1}, + {{&machine_pin_type}, GPIO_NUM_2}, + {{&machine_pin_type}, GPIO_NUM_3}, + {{&machine_pin_type}, GPIO_NUM_4}, + {{&machine_pin_type}, GPIO_NUM_5}, + {{&machine_pin_type}, GPIO_NUM_6}, + {{&machine_pin_type}, GPIO_NUM_7}, + {{&machine_pin_type}, GPIO_NUM_8}, + {{&machine_pin_type}, GPIO_NUM_9}, + {{&machine_pin_type}, GPIO_NUM_10}, + {{&machine_pin_type}, GPIO_NUM_11}, + {{&machine_pin_type}, GPIO_NUM_12}, + {{&machine_pin_type}, GPIO_NUM_13}, + {{&machine_pin_type}, GPIO_NUM_14}, + {{&machine_pin_type}, GPIO_NUM_15}, + {{&machine_pin_type}, GPIO_NUM_16}, + {{&machine_pin_type}, GPIO_NUM_17}, + {{&machine_pin_type}, GPIO_NUM_18}, + {{&machine_pin_type}, GPIO_NUM_19}, + {{NULL}, -1}, + {{&machine_pin_type}, GPIO_NUM_21}, + {{&machine_pin_type}, GPIO_NUM_22}, + {{&machine_pin_type}, GPIO_NUM_23}, + {{NULL}, -1}, + {{&machine_pin_type}, GPIO_NUM_25}, + {{&machine_pin_type}, GPIO_NUM_26}, + {{&machine_pin_type}, GPIO_NUM_27}, + {{NULL}, -1}, + {{NULL}, -1}, + {{NULL}, -1}, + {{NULL}, -1}, + {{&machine_pin_type}, GPIO_NUM_32}, + {{&machine_pin_type}, GPIO_NUM_33}, + {{&machine_pin_type}, GPIO_NUM_34}, + {{&machine_pin_type}, GPIO_NUM_35}, + {{&machine_pin_type}, GPIO_NUM_36}, + {{&machine_pin_type}, GPIO_NUM_37}, + {{&machine_pin_type}, GPIO_NUM_38}, + {{&machine_pin_type}, GPIO_NUM_39}, +}; + +// forward declaration +STATIC const machine_pin_irq_obj_t machine_pin_irq_object[]; + +void machine_pins_init(void) { + static bool did_install = false; + if (!did_install) { + gpio_install_isr_service(0); + did_install = true; + } + memset(&MP_STATE_PORT(machine_pin_irq_handler[0]), 0, sizeof(MP_STATE_PORT(machine_pin_irq_handler))); +} + +void machine_pins_deinit(void) { + for (int i = 0; i < MP_ARRAY_SIZE(machine_pin_obj); ++i) { + if (machine_pin_obj[i].id != (gpio_num_t)-1) { + gpio_isr_handler_remove(machine_pin_obj[i].id); + } + } +} + +STATIC void IRAM_ATTR machine_pin_isr_handler(void *arg) { + machine_pin_obj_t *self = arg; + mp_obj_t handler = MP_STATE_PORT(machine_pin_irq_handler)[self->id]; + mp_sched_schedule(handler, MP_OBJ_FROM_PTR(self)); +} + +gpio_num_t machine_pin_get_id(mp_obj_t pin_in) { + if (mp_obj_get_type(pin_in) != &machine_pin_type) { + mp_raise_ValueError("expecting a pin"); + } + machine_pin_obj_t *self = pin_in; + return self->id; +} + +STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_pin_obj_t *self = self_in; + mp_printf(print, "Pin(%u)", self->id); +} + +// pin.init(mode, pull=None, *, value) +STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_mode, ARG_pull, ARG_value }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = mp_const_none}}, + { MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none}}, + { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // configure the pin for gpio + gpio_pad_select_gpio(self->id); + + // set initial value (do this before configuring mode/pull) + if (args[ARG_value].u_obj != MP_OBJ_NULL) { + gpio_set_level(self->id, mp_obj_is_true(args[ARG_value].u_obj)); + } + + // configure mode + if (args[ARG_mode].u_obj != mp_const_none) { + mp_int_t pin_io_mode = mp_obj_get_int(args[ARG_mode].u_obj); + if (self->id >= 34 && (pin_io_mode & GPIO_MODE_DEF_OUTPUT)) { + mp_raise_ValueError("pin can only be input"); + } else { + gpio_set_direction(self->id, pin_io_mode); + } + } + + // configure pull + if (args[ARG_pull].u_obj != mp_const_none) { + gpio_set_pull_mode(self->id, mp_obj_get_int(args[ARG_pull].u_obj)); + } + + return mp_const_none; +} + +// constructor(id, ...) +mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // get the wanted pin object + int wanted_pin = mp_obj_get_int(args[0]); + const machine_pin_obj_t *self = NULL; + if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(machine_pin_obj)) { + self = (machine_pin_obj_t*)&machine_pin_obj[wanted_pin]; + } + if (self == NULL || self->base.type == NULL) { + mp_raise_ValueError("invalid pin"); + } + + if (n_args > 1 || n_kw > 0) { + // pin mode given, so configure this GPIO + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + machine_pin_obj_init_helper(self, n_args - 1, args + 1, &kw_args); + } + + return MP_OBJ_FROM_PTR(self); +} + +// fast method for getting/setting pin value +STATIC mp_obj_t machine_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + machine_pin_obj_t *self = self_in; + if (n_args == 0) { + // get pin + return MP_OBJ_NEW_SMALL_INT(gpio_get_level(self->id)); + } else { + // set pin + gpio_set_level(self->id, mp_obj_is_true(args[0])); + return mp_const_none; + } +} + +// pin.init(mode, pull) +STATIC mp_obj_t machine_pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_obj_init); + +// pin.value([value]) +STATIC mp_obj_t machine_pin_value(size_t n_args, const mp_obj_t *args) { + return machine_pin_call(args[0], n_args - 1, 0, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_pin_value); + +// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING) +STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_handler, ARG_trigger, ARG_hard }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_PIN_INTR_POSEDGE | GPIO_PIN_INTR_NEGEDGE} }, + }; + machine_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (n_args > 1 || kw_args->used != 0) { + // configure irq + mp_obj_t handler = args[ARG_handler].u_obj; + uint32_t trigger = args[ARG_trigger].u_int; + if (handler == mp_const_none) { + handler = MP_OBJ_NULL; + trigger = 0; + } + gpio_isr_handler_remove(self->id); + MP_STATE_PORT(machine_pin_irq_handler)[self->id] = handler; + gpio_set_intr_type(self->id, trigger); + gpio_isr_handler_add(self->id, machine_pin_isr_handler, (void*)self); + } + + // return the irq object + return MP_OBJ_FROM_PTR(&machine_pin_irq_object[self->id]); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_irq_obj, 1, machine_pin_irq); + +STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pin_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_pin_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_pin_irq_obj) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_MODE_INPUT) }, + { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_MODE_INPUT_OUTPUT) }, + { MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(GPIO_MODE_INPUT_OUTPUT_OD) }, + { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PULLUP_ONLY) }, + { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULLDOWN_ONLY) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_PIN_INTR_POSEDGE) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_PIN_INTR_NEGEDGE) }, +}; + +STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + (void)errcode; + machine_pin_obj_t *self = self_in; + + switch (request) { + case MP_PIN_READ: { + return gpio_get_level(self->id); + } + case MP_PIN_WRITE: { + gpio_set_level(self->id, arg); + return 0; + } + } + return -1; +} + +STATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table); + +STATIC const mp_pin_p_t pin_pin_p = { + .ioctl = pin_ioctl, +}; + +const mp_obj_type_t machine_pin_type = { + { &mp_type_type }, + .name = MP_QSTR_Pin, + .print = machine_pin_print, + .make_new = mp_pin_make_new, + .call = machine_pin_call, + .protocol = &pin_pin_p, + .locals_dict = (mp_obj_t)&machine_pin_locals_dict, +}; + +/******************************************************************************/ +// Pin IRQ object + +STATIC const mp_obj_type_t machine_pin_irq_type; + +STATIC const machine_pin_irq_obj_t machine_pin_irq_object[] = { + {{&machine_pin_irq_type}, GPIO_NUM_0}, + {{&machine_pin_irq_type}, GPIO_NUM_1}, + {{&machine_pin_irq_type}, GPIO_NUM_2}, + {{&machine_pin_irq_type}, GPIO_NUM_3}, + {{&machine_pin_irq_type}, GPIO_NUM_4}, + {{&machine_pin_irq_type}, GPIO_NUM_5}, + {{&machine_pin_irq_type}, GPIO_NUM_6}, + {{&machine_pin_irq_type}, GPIO_NUM_7}, + {{&machine_pin_irq_type}, GPIO_NUM_8}, + {{&machine_pin_irq_type}, GPIO_NUM_9}, + {{&machine_pin_irq_type}, GPIO_NUM_10}, + {{&machine_pin_irq_type}, GPIO_NUM_11}, + {{&machine_pin_irq_type}, GPIO_NUM_12}, + {{&machine_pin_irq_type}, GPIO_NUM_13}, + {{&machine_pin_irq_type}, GPIO_NUM_14}, + {{&machine_pin_irq_type}, GPIO_NUM_15}, + {{&machine_pin_irq_type}, GPIO_NUM_16}, + {{&machine_pin_irq_type}, GPIO_NUM_17}, + {{&machine_pin_irq_type}, GPIO_NUM_18}, + {{&machine_pin_irq_type}, GPIO_NUM_19}, + {{NULL}, -1}, + {{&machine_pin_irq_type}, GPIO_NUM_21}, + {{&machine_pin_irq_type}, GPIO_NUM_22}, + {{&machine_pin_irq_type}, GPIO_NUM_23}, + {{NULL}, -1}, + {{&machine_pin_irq_type}, GPIO_NUM_25}, + {{&machine_pin_irq_type}, GPIO_NUM_26}, + {{&machine_pin_irq_type}, GPIO_NUM_27}, + {{NULL}, -1}, + {{NULL}, -1}, + {{NULL}, -1}, + {{NULL}, -1}, + {{&machine_pin_irq_type}, GPIO_NUM_32}, + {{&machine_pin_irq_type}, GPIO_NUM_33}, + {{&machine_pin_irq_type}, GPIO_NUM_34}, + {{&machine_pin_irq_type}, GPIO_NUM_35}, + {{&machine_pin_irq_type}, GPIO_NUM_36}, + {{&machine_pin_irq_type}, GPIO_NUM_37}, + {{&machine_pin_irq_type}, GPIO_NUM_38}, + {{&machine_pin_irq_type}, GPIO_NUM_39}, +}; + +STATIC mp_obj_t machine_pin_irq_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + machine_pin_irq_obj_t *self = self_in; + mp_arg_check_num(n_args, n_kw, 0, 0, false); + machine_pin_isr_handler((void*)&machine_pin_obj[self->id]); + return mp_const_none; +} + +STATIC mp_obj_t machine_pin_irq_trigger(size_t n_args, const mp_obj_t *args) { + machine_pin_irq_obj_t *self = args[0]; + uint32_t orig_trig = GPIO.pin[self->id].int_type; + if (n_args == 2) { + // set trigger + gpio_set_intr_type(self->id, mp_obj_get_int(args[1])); + } + // return original trigger value + return MP_OBJ_NEW_SMALL_INT(orig_trig); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_irq_trigger_obj, 1, 2, machine_pin_irq_trigger); + +STATIC const mp_rom_map_elem_t machine_pin_irq_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_trigger), MP_ROM_PTR(&machine_pin_irq_trigger_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_pin_irq_locals_dict, machine_pin_irq_locals_dict_table); + +STATIC const mp_obj_type_t machine_pin_irq_type = { + { &mp_type_type }, + .name = MP_QSTR_IRQ, + .call = machine_pin_irq_call, + .locals_dict = (mp_obj_dict_t*)&machine_pin_irq_locals_dict, +}; diff --git a/ports/esp32/machine_pwm.c b/ports/esp32/machine_pwm.c new file mode 100644 index 0000000000..489833e7c2 --- /dev/null +++ b/ports/esp32/machine_pwm.c @@ -0,0 +1,277 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include "driver/ledc.h" +#include "esp_err.h" + +#include "py/nlr.h" +#include "py/runtime.h" +#include "modmachine.h" +#include "mphalport.h" + +// Forward dec'l +extern const mp_obj_type_t machine_pwm_type; + +typedef struct _esp32_pwm_obj_t { + mp_obj_base_t base; + gpio_num_t pin; + uint8_t active; + uint8_t channel; +} esp32_pwm_obj_t; + +// Which channel has which GPIO pin assigned? +// (-1 if not assigned) +STATIC int chan_gpio[LEDC_CHANNEL_MAX]; + +// Params for PW operation +// 5khz +#define PWFREQ (5000) +// High speed mode +#define PWMODE (LEDC_HIGH_SPEED_MODE) +// 10-bit resolution (compatible with esp8266 PWM) +#define PWRES (LEDC_TIMER_10_BIT) +// Timer 1 +#define PWTIMER (LEDC_TIMER_1) + +// Config of timer upon which we run all PWM'ed GPIO pins +STATIC bool pwm_inited = false; +STATIC ledc_timer_config_t timer_cfg = { + .bit_num = PWRES, + .freq_hz = PWFREQ, + .speed_mode = PWMODE, + .timer_num = PWTIMER +}; + +STATIC void pwm_init(void) { + + // Initial condition: no channels assigned + for (int x = 0; x < LEDC_CHANNEL_MAX; ++x) { + chan_gpio[x] = -1; + } + + // Init with default timer params + ledc_timer_config(&timer_cfg); +} + +STATIC int set_freq(int newval) { + int oval = timer_cfg.freq_hz; + + timer_cfg.freq_hz = newval; + if (ledc_timer_config(&timer_cfg) != ESP_OK) { + timer_cfg.freq_hz = oval; + return 0; + } + return 1; +} + +/******************************************************************************/ + +// MicroPython bindings for PWM + +STATIC void esp32_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "PWM(%u", self->pin); + if (self->active) { + mp_printf(print, ", freq=%u, duty=%u", timer_cfg.freq_hz, + ledc_get_duty(PWMODE, self->channel)); + } + mp_printf(print, ")"); +} + +STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self, + size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_freq, ARG_duty }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_freq, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_duty, MP_ARG_INT, {.u_int = -1} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, + MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + int channel; + int avail = -1; + + // Find a free PWM channel, also spot if our pin is + // already mentioned. + for (channel = 0; channel < LEDC_CHANNEL_MAX; ++channel) { + if (chan_gpio[channel] == self->pin) { + break; + } + if ((avail == -1) && (chan_gpio[channel] == -1)) { + avail = channel; + } + } + if (channel >= LEDC_CHANNEL_MAX) { + if (avail == -1) { + mp_raise_ValueError("out of PWM channels"); + } + channel = avail; + } + + // New PWM assignment + self->active = 1; + if (chan_gpio[channel] == -1) { + ledc_channel_config_t cfg = { + .channel = channel, + .duty = (1 << PWRES) / 2, + .gpio_num = self->pin, + .intr_type = LEDC_INTR_DISABLE, + .speed_mode = PWMODE, + .timer_sel = PWTIMER, + }; + if (ledc_channel_config(&cfg) != ESP_OK) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "PWM not supported on pin %d", self->pin)); + } + chan_gpio[channel] = self->pin; + self->channel = channel; + } + + // Maybe change PWM timer + int tval = args[ARG_freq].u_int; + if (tval != -1) { + if (tval != timer_cfg.freq_hz) { + if (!set_freq(tval)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Bad frequency %d", tval)); + } + } + } + + // Set duty cycle? + int dval = args[ARG_duty].u_int; + if (dval != -1) { + dval &= ((1 << PWRES)-1); + ledc_set_duty(PWMODE, channel, dval); + ledc_update_duty(PWMODE, channel); + } +} + +STATIC mp_obj_t esp32_pwm_make_new(const mp_obj_type_t *type, + size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + gpio_num_t pin_id = machine_pin_get_id(args[0]); + + // create PWM object from the given pin + esp32_pwm_obj_t *self = m_new_obj(esp32_pwm_obj_t); + self->base.type = &machine_pwm_type; + self->pin = pin_id; + self->active = 0; + self->channel = -1; + + // start the PWM subsystem if it's not already running + if (!pwm_inited) { + pwm_init(); + pwm_inited = true; + } + + // start the PWM running for this channel + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + esp32_pwm_init_helper(self, n_args - 1, args + 1, &kw_args); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t esp32_pwm_init(size_t n_args, + const mp_obj_t *args, mp_map_t *kw_args) { + esp32_pwm_init_helper(args[0], n_args - 1, args + 1, kw_args); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(esp32_pwm_init_obj, 1, esp32_pwm_init); + +STATIC mp_obj_t esp32_pwm_deinit(mp_obj_t self_in) { + esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); + int chan = self->channel; + + // Valid channel? + if ((chan >= 0) && (chan < LEDC_CHANNEL_MAX)) { + // Mark it unused, and tell the hardware to stop routing + chan_gpio[chan] = -1; + ledc_stop(PWMODE, chan, 0); + self->active = 0; + self->channel = -1; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_pwm_deinit_obj, esp32_pwm_deinit); + +STATIC mp_obj_t esp32_pwm_freq(size_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + // get + return MP_OBJ_NEW_SMALL_INT(timer_cfg.freq_hz); + } + + // set + int tval = mp_obj_get_int(args[1]); + if (!set_freq(tval)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Bad frequency %d", tval)); + } + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_pwm_freq_obj, 1, 2, esp32_pwm_freq); + +STATIC mp_obj_t esp32_pwm_duty(size_t n_args, const mp_obj_t *args) { + esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]); + int duty; + + if (n_args == 1) { + // get + duty = ledc_get_duty(PWMODE, self->channel); + return MP_OBJ_NEW_SMALL_INT(duty); + } + + // set + duty = mp_obj_get_int(args[1]); + duty &= ((1 << PWRES)-1); + ledc_set_duty(PWMODE, self->channel, duty); + ledc_update_duty(PWMODE, self->channel); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_pwm_duty_obj, + 1, 2, esp32_pwm_duty); + +STATIC const mp_rom_map_elem_t esp32_pwm_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&esp32_pwm_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&esp32_pwm_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&esp32_pwm_freq_obj) }, + { MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&esp32_pwm_duty_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(esp32_pwm_locals_dict, + esp32_pwm_locals_dict_table); + +const mp_obj_type_t machine_pwm_type = { + { &mp_type_type }, + .name = MP_QSTR_PWM, + .print = esp32_pwm_print, + .make_new = esp32_pwm_make_new, + .locals_dict = (mp_obj_dict_t*)&esp32_pwm_locals_dict, +}; diff --git a/ports/esp32/machine_timer.c b/ports/esp32/machine_timer.c new file mode 100644 index 0000000000..d75efb8fc1 --- /dev/null +++ b/ports/esp32/machine_timer.c @@ -0,0 +1,192 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "driver/timer.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "modmachine.h" + +#define TIMER_INTR_SEL TIMER_INTR_LEVEL +#define TIMER_DIVIDER 40000 +#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) + +#define TIMER_FLAGS 0 + +typedef struct _machine_timer_obj_t { + mp_obj_base_t base; + mp_uint_t group; + mp_uint_t index; + + mp_uint_t repeat; + mp_uint_t period; + + mp_obj_t callback; + + intr_handle_t handle; +} machine_timer_obj_t; + +const mp_obj_type_t machine_timer_type; + +STATIC esp_err_t check_esp_err(esp_err_t code) { + if (code) { + mp_raise_OSError(code); + } + + return code; +} + +STATIC void machine_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_timer_obj_t *self = self_in; + + timer_config_t config; + mp_printf(print, "Timer(%p; ", self); + + timer_get_config(self->group, self->index, &config); + + mp_printf(print, "alarm_en=%d, ", config.alarm_en); + mp_printf(print, "auto_reload=%d, ", config.auto_reload); + mp_printf(print, "counter_en=%d)", config.counter_en); +} + +STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + machine_timer_obj_t *self = m_new_obj(machine_timer_obj_t); + self->base.type = &machine_timer_type; + + self->group = (mp_obj_get_int(args[0]) >> 1) & 1; + self->index = mp_obj_get_int(args[0]) & 1; + + return self; +} + +STATIC void machine_timer_disable(machine_timer_obj_t *self) { + if (self->handle) { + timer_pause(self->group, self->index); + esp_intr_free(self->handle); + self->handle = NULL; + } +} + +STATIC void machine_timer_isr(void *self_in) { + machine_timer_obj_t *self = self_in; + timg_dev_t *device = self->group ? &(TIMERG1) : &(TIMERG0); + + device->hw_timer[self->index].update = 1; + if (self->index) { + device->int_clr_timers.t1 = 1; + } else { + device->int_clr_timers.t0 = 1; + } + device->hw_timer[self->index].config.alarm_en = self->repeat; + + mp_sched_schedule(self->callback, self); +} + +STATIC void machine_timer_enable(machine_timer_obj_t *self) { + timer_config_t config; + config.alarm_en = TIMER_ALARM_EN; + config.auto_reload = self->repeat; + config.counter_dir = TIMER_COUNT_UP; + config.divider = TIMER_DIVIDER; + config.intr_type = TIMER_INTR_LEVEL; + config.counter_en = TIMER_PAUSE; + + check_esp_err(timer_init(self->group, self->index, &config)); + check_esp_err(timer_set_counter_value(self->group, self->index, 0x00000000)); + check_esp_err(timer_set_alarm_value(self->group, self->index, self->period)); + check_esp_err(timer_enable_intr(self->group, self->index)); + check_esp_err(timer_isr_register(self->group, self->index, machine_timer_isr, (void*)self, TIMER_FLAGS, &self->handle)); + check_esp_err(timer_start(self->group, self->index)); +} + +STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, + { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + machine_timer_disable(self); + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // Timer uses an 80MHz base clock, which is divided by the divider/scalar, we then convert to ms. + self->period = (args[0].u_int * TIMER_BASE_CLK) / (1000 * TIMER_DIVIDER); + self->repeat = args[1].u_int; + self->callback = args[2].u_obj; + self->handle = NULL; + + machine_timer_enable(self); + + return mp_const_none; +} + +STATIC mp_obj_t machine_timer_deinit(mp_obj_t self_in) { + machine_timer_disable(self_in); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_deinit_obj, machine_timer_deinit); + +STATIC mp_obj_t machine_timer_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return machine_timer_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_timer_init_obj, 1, machine_timer_init); + +STATIC mp_obj_t machine_timer_value(mp_obj_t self_in) { + machine_timer_obj_t *self = self_in; + double result; + + timer_get_counter_time_sec(self->group, self->index, &result); + + return MP_OBJ_NEW_SMALL_INT((mp_uint_t)(result * 1000)); // value in ms +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_value_obj, machine_timer_value); + +STATIC const mp_map_elem_t machine_timer_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), (mp_obj_t)&machine_timer_deinit_obj }, + { MP_ROM_QSTR(MP_QSTR_deinit), (mp_obj_t)&machine_timer_deinit_obj }, + { MP_ROM_QSTR(MP_QSTR_init), (mp_obj_t)&machine_timer_init_obj }, + { MP_ROM_QSTR(MP_QSTR_value), (mp_obj_t)&machine_timer_value_obj }, + { MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(false) }, + { MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(true) }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_timer_locals_dict, machine_timer_locals_dict_table); + +const mp_obj_type_t machine_timer_type = { + { &mp_type_type }, + .name = MP_QSTR_Timer, + .print = machine_timer_print, + .make_new = machine_timer_make_new, + .locals_dict = (mp_obj_t)&machine_timer_locals_dict, +}; diff --git a/ports/esp32/machine_touchpad.c b/ports/esp32/machine_touchpad.c new file mode 100644 index 0000000000..96de1a2a1d --- /dev/null +++ b/ports/esp32/machine_touchpad.c @@ -0,0 +1,110 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Nick Moore + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include + +#include "esp_log.h" + +#include "driver/gpio.h" +#include "driver/touch_pad.h" + +#include "py/runtime.h" +#include "py/mphal.h" +#include "modmachine.h" + +typedef struct _mtp_obj_t { + mp_obj_base_t base; + gpio_num_t gpio_id; + touch_pad_t touchpad_id; +} mtp_obj_t; + +STATIC const mtp_obj_t touchpad_obj[] = { + {{&machine_touchpad_type}, GPIO_NUM_4, TOUCH_PAD_NUM0}, + {{&machine_touchpad_type}, GPIO_NUM_0, TOUCH_PAD_NUM1}, + {{&machine_touchpad_type}, GPIO_NUM_2, TOUCH_PAD_NUM2}, + {{&machine_touchpad_type}, GPIO_NUM_15, TOUCH_PAD_NUM3}, + {{&machine_touchpad_type}, GPIO_NUM_13, TOUCH_PAD_NUM4}, + {{&machine_touchpad_type}, GPIO_NUM_12, TOUCH_PAD_NUM5}, + {{&machine_touchpad_type}, GPIO_NUM_14, TOUCH_PAD_NUM6}, + {{&machine_touchpad_type}, GPIO_NUM_27, TOUCH_PAD_NUM7}, + {{&machine_touchpad_type}, GPIO_NUM_33, TOUCH_PAD_NUM8}, + {{&machine_touchpad_type}, GPIO_NUM_32, TOUCH_PAD_NUM9}, +}; + +STATIC mp_obj_t mtp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, + const mp_obj_t *args) { + + mp_arg_check_num(n_args, n_kw, 1, 1, true); + gpio_num_t pin_id = machine_pin_get_id(args[0]); + const mtp_obj_t *self = NULL; + for (int i = 0; i < MP_ARRAY_SIZE(touchpad_obj); i++) { + if (pin_id == touchpad_obj[i].gpio_id) { self = &touchpad_obj[i]; break; } + } + if (!self) mp_raise_ValueError("invalid pin for touchpad"); + + static int initialized = 0; + if (!initialized) { + touch_pad_init(); + initialized = 1; + } + esp_err_t err = touch_pad_config(self->touchpad_id, 0); + if (err == ESP_OK) return MP_OBJ_FROM_PTR(self); + mp_raise_ValueError("Touch pad error"); +} + +STATIC mp_obj_t mtp_config(mp_obj_t self_in, mp_obj_t value_in) { + mtp_obj_t *self = self_in; + uint16_t value = mp_obj_get_int(value_in); + esp_err_t err = touch_pad_config(self->touchpad_id, value); + if (err == ESP_OK) return mp_const_none; + mp_raise_ValueError("Touch pad error"); +} +MP_DEFINE_CONST_FUN_OBJ_2(mtp_config_obj, mtp_config); + +STATIC mp_obj_t mtp_read(mp_obj_t self_in) { + mtp_obj_t *self = self_in; + uint16_t value; + esp_err_t err = touch_pad_read(self->touchpad_id, &value); + if (err == ESP_OK) return MP_OBJ_NEW_SMALL_INT(value); + mp_raise_ValueError("Touch pad error"); +} +MP_DEFINE_CONST_FUN_OBJ_1(mtp_read_obj, mtp_read); + +STATIC const mp_rom_map_elem_t mtp_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&mtp_config_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mtp_read_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mtp_locals_dict, mtp_locals_dict_table); + +const mp_obj_type_t machine_touchpad_type = { + { &mp_type_type }, + .name = MP_QSTR_TouchPad, + .make_new = mtp_make_new, + .locals_dict = (mp_obj_t)&mtp_locals_dict, +}; diff --git a/ports/esp32/machine_uart.c b/ports/esp32/machine_uart.c new file mode 100644 index 0000000000..0b303d424d --- /dev/null +++ b/ports/esp32/machine_uart.c @@ -0,0 +1,359 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "driver/uart.h" +#include "freertos/FreeRTOS.h" + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "modmachine.h" + +typedef struct _machine_uart_obj_t { + mp_obj_base_t base; + uart_port_t uart_num; + uint8_t bits; + uint8_t parity; + uint8_t stop; + int8_t tx; + int8_t rx; + int8_t rts; + int8_t cts; + uint16_t timeout; // timeout waiting for first char (in ms) + uint16_t timeout_char; // timeout waiting between chars (in ms) +} machine_uart_obj_t; + +STATIC const char *_parity_name[] = {"None", "1", "0"}; + +QueueHandle_t UART_QUEUE[UART_NUM_MAX] = {}; + +/******************************************************************************/ +// MicroPython bindings for UART + +STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint32_t baudrate; + uart_get_baudrate(self->uart_num, &baudrate); + mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, tx=%d, rx=%d, rts=%d, cts=%d, timeout=%u, timeout_char=%u)", + self->uart_num, baudrate, self->bits, _parity_name[self->parity], + self->stop, self->tx, self->rx, self->rts, self->cts, self->timeout, self->timeout_char); +} + +STATIC void machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx, ARG_rts, ARG_cts, ARG_timeout, ARG_timeout_char }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_bits, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_stop, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_tx, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} }, + { MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} }, + { MP_QSTR_rts, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} }, + { MP_QSTR_cts, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // wait for all data to be transmitted before changing settings + uart_wait_tx_done(self->uart_num, pdMS_TO_TICKS(1000)); + + // set baudrate + uint32_t baudrate = 115200; + if (args[ARG_baudrate].u_int > 0) { + uart_set_baudrate(self->uart_num, args[ARG_baudrate].u_int); + uart_get_baudrate(self->uart_num, &baudrate); + } + + uart_set_pin(self->uart_num, args[ARG_tx].u_int, args[ARG_rx].u_int, args[ARG_rts].u_int, args[ARG_cts].u_int); + if (args[ARG_tx].u_int != UART_PIN_NO_CHANGE) { + self->tx = args[ARG_tx].u_int; + } + + if (args[ARG_rx].u_int != UART_PIN_NO_CHANGE) { + self->rx = args[ARG_rx].u_int; + } + + if (args[ARG_rts].u_int != UART_PIN_NO_CHANGE) { + self->rts = args[ARG_rts].u_int; + } + + if (args[ARG_cts].u_int != UART_PIN_NO_CHANGE) { + self->cts = args[ARG_cts].u_int; + } + + // set data bits + switch (args[ARG_bits].u_int) { + case 0: + break; + case 5: + uart_set_word_length(self->uart_num, UART_DATA_5_BITS); + self->bits = 5; + break; + case 6: + uart_set_word_length(self->uart_num, UART_DATA_6_BITS); + self->bits = 6; + break; + case 7: + uart_set_word_length(self->uart_num, UART_DATA_7_BITS); + self->bits = 7; + break; + case 8: + uart_set_word_length(self->uart_num, UART_DATA_8_BITS); + self->bits = 8; + break; + default: + mp_raise_ValueError("invalid data bits"); + break; + } + + // set parity + if (args[ARG_parity].u_obj != MP_OBJ_NULL) { + if (args[ARG_parity].u_obj == mp_const_none) { + uart_set_parity(self->uart_num, UART_PARITY_DISABLE); + self->parity = 0; + } else { + mp_int_t parity = mp_obj_get_int(args[ARG_parity].u_obj); + if (parity & 1) { + uart_set_parity(self->uart_num, UART_PARITY_ODD); + self->parity = 1; + } else { + uart_set_parity(self->uart_num, UART_PARITY_EVEN); + self->parity = 2; + } + } + } + + // set stop bits + switch (args[ARG_stop].u_int) { + // FIXME: ESP32 also supports 1.5 stop bits + case 0: + break; + case 1: + uart_set_stop_bits(self->uart_num, UART_STOP_BITS_1); + self->stop = 1; + break; + case 2: + uart_set_stop_bits(self->uart_num, UART_STOP_BITS_2); + self->stop = 2; + break; + default: + mp_raise_ValueError("invalid stop bits"); + break; + } + + // set timeout + self->timeout = args[ARG_timeout].u_int; + + // set timeout_char + // make sure it is at least as long as a whole character (13 bits to be safe) + self->timeout_char = args[ARG_timeout_char].u_int; + uint32_t min_timeout_char = 13000 / baudrate + 1; + if (self->timeout_char < min_timeout_char) { + self->timeout_char = min_timeout_char; + } +} + +STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // get uart id + mp_int_t uart_num = mp_obj_get_int(args[0]); + if (uart_num < 0 || uart_num > UART_NUM_MAX) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) does not exist", uart_num)); + } + + // Attempts to use UART0 from Python has resulted in all sorts of fun errors. + // FIXME: UART0 is disabled for now. + if (uart_num == UART_NUM_0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) is disabled (dedicated to REPL)", uart_num)); + } + + // Defaults + uart_config_t uartcfg = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .rx_flow_ctrl_thresh = 0 + }; + + // create instance + machine_uart_obj_t *self = m_new_obj(machine_uart_obj_t); + self->base.type = &machine_uart_type; + self->uart_num = uart_num; + self->bits = 8; + self->parity = 0; + self->stop = 1; + self->rts = UART_PIN_NO_CHANGE; + self->cts = UART_PIN_NO_CHANGE; + self->timeout = 0; + self->timeout_char = 0; + + switch (uart_num) { + case UART_NUM_0: + self->rx = UART_PIN_NO_CHANGE; // GPIO 3 + self->tx = UART_PIN_NO_CHANGE; // GPIO 1 + break; + case UART_NUM_1: + self->rx = 9; + self->tx = 10; + break; + case UART_NUM_2: + self->rx = 16; + self->tx = 17; + break; + } + + // Remove any existing configuration + uart_driver_delete(self->uart_num); + + // init the peripheral + // Setup + uart_param_config(self->uart_num, &uartcfg); + + // RX and TX buffers are currently hardcoded at 256 bytes each (IDF minimum). + uart_driver_install(uart_num, 256, 256, 10, &UART_QUEUE[self->uart_num], 0); + + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + machine_uart_init_helper(self, n_args - 1, args + 1, &kw_args); + + // Make sure pins are connected. + uart_set_pin(self->uart_num, self->tx, self->rx, self->rts, self->cts); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t machine_uart_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + machine_uart_init_helper(args[0], n_args - 1, args + 1, kw_args); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(machine_uart_init_obj, 1, machine_uart_init); + +STATIC mp_obj_t machine_uart_any(mp_obj_t self_in) { + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + size_t rxbufsize; + uart_get_buffered_data_len(self->uart_num, &rxbufsize); + return MP_OBJ_NEW_SMALL_INT(rxbufsize); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_any_obj, machine_uart_any); + +STATIC const mp_rom_map_elem_t machine_uart_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_uart_init_obj) }, + + { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&machine_uart_any_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_uart_locals_dict, machine_uart_locals_dict_table); + +STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // make sure we want at least 1 char + if (size == 0) { + return 0; + } + + TickType_t time_to_wait; + if (self->timeout == 0) { + time_to_wait = 0; + } else { + time_to_wait = pdMS_TO_TICKS(self->timeout); + } + + int bytes_read = uart_read_bytes(self->uart_num, buf_in, size, time_to_wait); + + if (bytes_read < 0) { + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } + + return bytes_read; +} + +STATIC mp_uint_t machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + + int bytes_written = uart_write_bytes(self->uart_num, buf_in, size); + + if (bytes_written < 0) { + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } + + // return number of bytes written + return bytes_written; +} + +STATIC mp_uint_t machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { + machine_uart_obj_t *self = self_in; + mp_uint_t ret; + if (request == MP_STREAM_POLL) { + mp_uint_t flags = arg; + ret = 0; + size_t rxbufsize; + uart_get_buffered_data_len(self->uart_num, &rxbufsize); + if ((flags & MP_STREAM_POLL_RD) && rxbufsize > 0) { + ret |= MP_STREAM_POLL_RD; + } + if ((flags & MP_STREAM_POLL_WR) && 1) { // FIXME: uart_tx_any_room(self->uart_num) + ret |= MP_STREAM_POLL_WR; + } + } else { + *errcode = MP_EINVAL; + ret = MP_STREAM_ERROR; + } + return ret; +} + +STATIC const mp_stream_p_t uart_stream_p = { + .read = machine_uart_read, + .write = machine_uart_write, + .ioctl = machine_uart_ioctl, + .is_text = false, +}; + +const mp_obj_type_t machine_uart_type = { + { &mp_type_type }, + .name = MP_QSTR_UART, + .print = machine_uart_print, + .make_new = machine_uart_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &uart_stream_p, + .locals_dict = (mp_obj_dict_t*)&machine_uart_locals_dict, +}; diff --git a/ports/esp32/main.c b/ports/esp32/main.c new file mode 100644 index 0000000000..091cbddc98 --- /dev/null +++ b/ports/esp32/main.c @@ -0,0 +1,131 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "nvs_flash.h" +#include "esp_task.h" +#include "soc/cpu.h" + +#include "py/stackctrl.h" +#include "py/nlr.h" +#include "py/compile.h" +#include "py/runtime.h" +#include "py/repl.h" +#include "py/gc.h" +#include "py/mphal.h" +#include "lib/mp-readline/readline.h" +#include "lib/utils/pyexec.h" +#include "uart.h" +#include "modmachine.h" +#include "mpthreadport.h" + +// MicroPython runs as a task under FreeRTOS +#define MP_TASK_PRIORITY (ESP_TASK_PRIO_MIN + 1) +#define MP_TASK_STACK_SIZE (16 * 1024) +#define MP_TASK_STACK_LEN (MP_TASK_STACK_SIZE / sizeof(StackType_t)) +#define MP_TASK_HEAP_SIZE (96 * 1024) + +STATIC StaticTask_t mp_task_tcb; +STATIC StackType_t mp_task_stack[MP_TASK_STACK_LEN] __attribute__((aligned (8))); +STATIC uint8_t mp_task_heap[MP_TASK_HEAP_SIZE]; + +void mp_task(void *pvParameter) { + volatile uint32_t sp = (uint32_t)get_sp(); + #if MICROPY_PY_THREAD + mp_thread_init(&mp_task_stack[0], MP_TASK_STACK_LEN); + #endif + uart_init(); + +soft_reset: + // initialise the stack pointer for the main thread + mp_stack_set_top((void *)sp); + mp_stack_set_limit(MP_TASK_STACK_SIZE - 1024); + gc_init(mp_task_heap, mp_task_heap + sizeof(mp_task_heap)); + mp_init(); + mp_obj_list_init(mp_sys_path, 0); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib)); + mp_obj_list_init(mp_sys_argv, 0); + readline_init0(); + + // initialise peripherals + machine_pins_init(); + + // run boot-up scripts + pyexec_frozen_module("_boot.py"); + pyexec_file("boot.py"); + if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) { + pyexec_file("main.py"); + } + + for (;;) { + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + if (pyexec_raw_repl() != 0) { + break; + } + } else { + if (pyexec_friendly_repl() != 0) { + break; + } + } + } + + #if MICROPY_PY_THREAD + mp_thread_deinit(); + #endif + + mp_hal_stdout_tx_str("PYB: soft reboot\r\n"); + + // deinitialise peripherals + machine_pins_deinit(); + + mp_deinit(); + fflush(stdout); + goto soft_reset; +} + +void app_main(void) { + nvs_flash_init(); + xTaskCreateStaticPinnedToCore(mp_task, "mp_task", MP_TASK_STACK_LEN, NULL, MP_TASK_PRIORITY, + &mp_task_stack[0], &mp_task_tcb, 0); +} + +void nlr_jump_fail(void *val) { + printf("NLR jump failed, val=%p\n", val); + esp_restart(); +} + +// modussl_mbedtls uses this function but it's not enabled in ESP IDF +void mbedtls_debug_set_threshold(int threshold) { + (void)threshold; +} diff --git a/ports/esp32/makeimg.py b/ports/esp32/makeimg.py new file mode 100644 index 0000000000..aeedbff7ef --- /dev/null +++ b/ports/esp32/makeimg.py @@ -0,0 +1,25 @@ +import sys + +OFFSET_BOOTLOADER = 0x1000 +OFFSET_PARTITIONS = 0x8000 +OFFSET_APPLICATION = 0x10000 + +files_in = [ + ('bootloader', OFFSET_BOOTLOADER, sys.argv[1]), + ('partitions', OFFSET_PARTITIONS, sys.argv[2]), + ('application', OFFSET_APPLICATION, sys.argv[3]), +] +file_out = sys.argv[4] + +cur_offset = OFFSET_BOOTLOADER +with open(file_out, 'wb') as fout: + for name, offset, file_in in files_in: + assert offset >= cur_offset + fout.write(b'\xff' * (offset - cur_offset)) + cur_offset = offset + with open(file_in, 'rb') as fin: + data = fin.read() + fout.write(data) + cur_offset += len(data) + print('%-12s% 8d' % (name, len(data))) + print('%-12s% 8d' % ('total', cur_offset)) diff --git a/ports/esp32/memory.h b/ports/esp32/memory.h new file mode 100644 index 0000000000..f3777b0e39 --- /dev/null +++ b/ports/esp32/memory.h @@ -0,0 +1,2 @@ +// this is needed for extmod/crypto-algorithms/sha256.c +#include diff --git a/ports/esp32/modesp.c b/ports/esp32/modesp.c new file mode 100644 index 0000000000..caa0551646 --- /dev/null +++ b/ports/esp32/modesp.c @@ -0,0 +1,129 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Paul Sokolovsky + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "rom/gpio.h" +#include "esp_spi_flash.h" + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "drivers/dht/dht.h" +#include "modesp.h" + +STATIC mp_obj_t esp_flash_read(mp_obj_t offset_in, mp_obj_t buf_in) { + mp_int_t offset = mp_obj_get_int(offset_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); + esp_err_t res = spi_flash_read(offset, bufinfo.buf, bufinfo.len); + if (res != ESP_OK) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_read_obj, esp_flash_read); + +STATIC mp_obj_t esp_flash_write(mp_obj_t offset_in, mp_obj_t buf_in) { + mp_int_t offset = mp_obj_get_int(offset_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + esp_err_t res = spi_flash_write(offset, bufinfo.buf, bufinfo.len); + if (res != ESP_OK) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_write_obj, esp_flash_write); + +STATIC mp_obj_t esp_flash_erase(mp_obj_t sector_in) { + mp_int_t sector = mp_obj_get_int(sector_in); + esp_err_t res = spi_flash_erase_sector(sector); + if (res != ESP_OK) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_flash_erase_obj, esp_flash_erase); + +STATIC mp_obj_t esp_flash_size(void) { + return mp_obj_new_int_from_uint(spi_flash_get_chip_size()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_size_obj, esp_flash_size); + +STATIC mp_obj_t esp_flash_user_start(void) { + return MP_OBJ_NEW_SMALL_INT(0x200000); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_user_start_obj, esp_flash_user_start); + +STATIC mp_obj_t esp_gpio_matrix_in(mp_obj_t pin, mp_obj_t sig, mp_obj_t inv) { + gpio_matrix_in(mp_obj_get_int(pin), mp_obj_get_int(sig), mp_obj_get_int(inv)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_gpio_matrix_in_obj, esp_gpio_matrix_in); + +STATIC mp_obj_t esp_gpio_matrix_out(size_t n_args, const mp_obj_t *args) { + (void)n_args; + gpio_matrix_out(mp_obj_get_int(args[0]), mp_obj_get_int(args[1]), mp_obj_get_int(args[2]), mp_obj_get_int(args[3])); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_gpio_matrix_out_obj, 4, 4, esp_gpio_matrix_out); + +STATIC mp_obj_t esp_neopixel_write_(mp_obj_t pin, mp_obj_t buf, mp_obj_t timing) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); + esp_neopixel_write(mp_hal_get_pin_obj(pin), + (uint8_t*)bufinfo.buf, bufinfo.len, mp_obj_get_int(timing)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_neopixel_write_obj, esp_neopixel_write_); + +STATIC const mp_rom_map_elem_t esp_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp) }, + + { MP_ROM_QSTR(MP_QSTR_flash_read), MP_ROM_PTR(&esp_flash_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_write), MP_ROM_PTR(&esp_flash_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_erase), MP_ROM_PTR(&esp_flash_erase_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_size), MP_ROM_PTR(&esp_flash_size_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_user_start), MP_ROM_PTR(&esp_flash_user_start_obj) }, + + { MP_ROM_QSTR(MP_QSTR_gpio_matrix_in), MP_ROM_PTR(&esp_gpio_matrix_in_obj) }, + { MP_ROM_QSTR(MP_QSTR_gpio_matrix_out), MP_ROM_PTR(&esp_gpio_matrix_out_obj) }, + + { MP_ROM_QSTR(MP_QSTR_neopixel_write), MP_ROM_PTR(&esp_neopixel_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(esp_module_globals, esp_module_globals_table); + +const mp_obj_module_t esp_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&esp_module_globals, +}; + diff --git a/ports/esp32/modesp.h b/ports/esp32/modesp.h new file mode 100644 index 0000000000..a822c02ecc --- /dev/null +++ b/ports/esp32/modesp.h @@ -0,0 +1 @@ +void esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t timing); diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c new file mode 100644 index 0000000000..51038f3141 --- /dev/null +++ b/ports/esp32/modmachine.c @@ -0,0 +1,135 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "rom/ets_sys.h" +#include "esp_system.h" + +#include "py/obj.h" +#include "py/runtime.h" +#include "extmod/machine_mem.h" +#include "extmod/machine_signal.h" +#include "extmod/machine_pulse.h" +#include "extmod/machine_i2c.h" +#include "extmod/machine_spi.h" +#include "modmachine.h" + +#if MICROPY_PY_MACHINE + +STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + // get + return mp_obj_new_int(ets_get_cpu_frequency() * 1000000); + } else { + // set + mp_int_t freq = mp_obj_get_int(args[0]) / 1000000; + if (freq != 80 && freq != 160 && freq != 240) { + mp_raise_ValueError("frequency can only be either 80Mhz, 160MHz or 240MHz"); + } + /* + system_update_cpu_freq(freq); + */ + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 1, machine_freq); + +STATIC mp_obj_t machine_reset(void) { + esp_restart(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset); + +STATIC mp_obj_t machine_unique_id(void) { + uint8_t chipid[6]; + esp_efuse_mac_get_default(chipid); + return mp_obj_new_bytes(chipid, 6); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id); + +STATIC mp_obj_t machine_idle(void) { + taskYIELD(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle); + +STATIC mp_obj_t machine_disable_irq(void) { + uint32_t state = MICROPY_BEGIN_ATOMIC_SECTION(); + return mp_obj_new_int(state); +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_disable_irq_obj, machine_disable_irq); + +STATIC mp_obj_t machine_enable_irq(mp_obj_t state_in) { + uint32_t state = mp_obj_get_int(state_in); + MICROPY_END_ATOMIC_SECTION(state); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(machine_enable_irq_obj, machine_enable_irq); + +STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) }, + + { MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) }, + + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) }, + + { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) }, + + { MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) }, + + { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) }, + { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, + { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, + { MP_ROM_QSTR(MP_QSTR_TouchPad), MP_ROM_PTR(&machine_touchpad_type) }, + { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&machine_adc_type) }, + { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&machine_dac_type) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, + { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_pwm_type) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&mp_machine_soft_spi_type) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); + +const mp_obj_module_t mp_module_machine = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&machine_module_globals, +}; + +#endif // MICROPY_PY_MACHINE diff --git a/ports/esp32/modmachine.h b/ports/esp32/modmachine.h new file mode 100644 index 0000000000..4909235b46 --- /dev/null +++ b/ports/esp32/modmachine.h @@ -0,0 +1,18 @@ +#ifndef MICROPY_INCLUDED_ESP32_MODMACHINE_H +#define MICROPY_INCLUDED_ESP32_MODMACHINE_H + +#include "py/obj.h" + +extern const mp_obj_type_t machine_timer_type; +extern const mp_obj_type_t machine_pin_type; +extern const mp_obj_type_t machine_touchpad_type; +extern const mp_obj_type_t machine_adc_type; +extern const mp_obj_type_t machine_dac_type; +extern const mp_obj_type_t machine_pwm_type; +extern const mp_obj_type_t machine_hw_spi_type; +extern const mp_obj_type_t machine_uart_type; + +void machine_pins_init(void); +void machine_pins_deinit(void); + +#endif // MICROPY_INCLUDED_ESP32_MODMACHINE_H diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c new file mode 100644 index 0000000000..73a4718617 --- /dev/null +++ b/ports/esp32/modnetwork.c @@ -0,0 +1,561 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * and Mnemote Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016, 2017 Nick Moore @mnemote + * + * Based on esp8266/modnetwork.c which is Copyright (c) 2015 Paul Sokolovsky + * And the ESP IDF example code which is Public Domain / CC0 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/nlr.h" +#include "py/objlist.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "py/mperrno.h" +#include "netutils.h" +#include "esp_wifi.h" +#include "esp_wifi_types.h" +#include "esp_log.h" +#include "esp_event_loop.h" +#include "esp_log.h" +#include "lwip/dns.h" +#include "tcpip_adapter.h" + +#define MODNETWORK_INCLUDE_CONSTANTS (1) + +NORETURN void _esp_exceptions(esp_err_t e) { + switch (e) { + case ESP_ERR_WIFI_NOT_INIT: + mp_raise_msg(&mp_type_OSError, "Wifi Not Initialized"); + case ESP_ERR_WIFI_NOT_STARTED: + mp_raise_msg(&mp_type_OSError, "Wifi Not Started"); + case ESP_ERR_WIFI_CONN: + mp_raise_msg(&mp_type_OSError, "Wifi Internal Error"); + case ESP_ERR_WIFI_SSID: + mp_raise_msg(&mp_type_OSError, "Wifi SSID Invalid"); + case ESP_ERR_WIFI_FAIL: + mp_raise_msg(&mp_type_OSError, "Wifi Internal Failure"); + case ESP_ERR_WIFI_IF: + mp_raise_msg(&mp_type_OSError, "Wifi Invalid Interface"); + case ESP_ERR_WIFI_MAC: + mp_raise_msg(&mp_type_OSError, "Wifi Invalid MAC Address"); + case ESP_ERR_WIFI_ARG: + mp_raise_msg(&mp_type_OSError, "Wifi Invalid Argument"); + case ESP_ERR_WIFI_MODE: + mp_raise_msg(&mp_type_OSError, "Wifi Invalid Mode"); + case ESP_ERR_WIFI_PASSWORD: + mp_raise_msg(&mp_type_OSError, "Wifi Invalid Password"); + case ESP_ERR_WIFI_NVS: + mp_raise_msg(&mp_type_OSError, "Wifi Internal NVS Error"); + case ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS: + mp_raise_msg(&mp_type_OSError, "TCP/IP Invalid Parameters"); + case ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY: + mp_raise_msg(&mp_type_OSError, "TCP/IP IF Not Ready"); + case ESP_ERR_TCPIP_ADAPTER_DHCPC_START_FAILED: + mp_raise_msg(&mp_type_OSError, "TCP/IP DHCP Client Start Failed"); + case ESP_ERR_WIFI_TIMEOUT: + mp_raise_OSError(MP_ETIMEDOUT); + case ESP_ERR_TCPIP_ADAPTER_NO_MEM: + case ESP_ERR_WIFI_NO_MEM: + mp_raise_OSError(MP_ENOMEM); + default: + nlr_raise(mp_obj_new_exception_msg_varg( + &mp_type_RuntimeError, "Wifi Unknown Error 0x%04x", e + )); + } +} + +static inline void esp_exceptions(esp_err_t e) { + if (e != ESP_OK) _esp_exceptions(e); +} + +#define ESP_EXCEPTIONS(x) do { esp_exceptions(x); } while (0); + +typedef struct _wlan_if_obj_t { + mp_obj_base_t base; + int if_id; +} wlan_if_obj_t; + +const mp_obj_type_t wlan_if_type; +STATIC const wlan_if_obj_t wlan_sta_obj = {{&wlan_if_type}, WIFI_IF_STA}; +STATIC const wlan_if_obj_t wlan_ap_obj = {{&wlan_if_type}, WIFI_IF_AP}; + +//static wifi_config_t wifi_ap_config = {{{0}}}; +static wifi_config_t wifi_sta_config = {{{0}}}; + +// Set to "true" if the STA interface is requested to be connected by the +// user, used for automatic reassociation. +static bool wifi_sta_connected = false; + +// This function is called by the system-event task and so runs in a different +// thread to the main MicroPython task. It must not raise any Python exceptions. +static esp_err_t event_handler(void *ctx, system_event_t *event) { + switch(event->event_id) { + case SYSTEM_EVENT_STA_START: + ESP_LOGI("wifi", "STA_START"); + break; + case SYSTEM_EVENT_STA_GOT_IP: + ESP_LOGI("wifi", "GOT_IP"); + break; + case SYSTEM_EVENT_STA_DISCONNECTED: { + // This is a workaround as ESP32 WiFi libs don't currently + // auto-reassociate. + system_event_sta_disconnected_t *disconn = &event->event_info.disconnected; + ESP_LOGI("wifi", "STA_DISCONNECTED, reason:%d", disconn->reason); + switch (disconn->reason) { + case WIFI_REASON_AUTH_FAIL: + mp_printf(MP_PYTHON_PRINTER, "authentication failed"); + wifi_sta_connected = false; + break; + default: + // Let other errors through and try to reconnect. + break; + } + if (wifi_sta_connected) { + wifi_mode_t mode; + if (esp_wifi_get_mode(&mode) == ESP_OK) { + if (mode & WIFI_MODE_STA) { + // STA is active so attempt to reconnect. + esp_err_t e = esp_wifi_connect(); + if (e != ESP_OK) { + mp_printf(MP_PYTHON_PRINTER, "error attempting to reconnect: 0x%04x", e); + } + } + } + } + break; + } + default: + ESP_LOGI("wifi", "event %d", event->event_id); + break; + } + return ESP_OK; +} + +/*void error_check(bool status, const char *msg) { + if (!status) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, msg)); + } +} +*/ + +STATIC void require_if(mp_obj_t wlan_if, int if_no) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(wlan_if); + if (self->if_id != if_no) { + mp_raise_msg(&mp_type_OSError, if_no == WIFI_IF_STA ? "STA required" : "AP required"); + } +} + +STATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args) { + int idx = (n_args > 0) ? mp_obj_get_int(args[0]) : WIFI_IF_STA; + if (idx == WIFI_IF_STA) { + return MP_OBJ_FROM_PTR(&wlan_sta_obj); + } else if (idx == WIFI_IF_AP) { + return MP_OBJ_FROM_PTR(&wlan_ap_obj); + } else { + mp_raise_ValueError("invalid WLAN interface identifier"); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_wlan_obj, 0, 1, get_wlan); + +STATIC mp_obj_t esp_initialize() { + static int initialized = 0; + if (!initialized) { + ESP_LOGD("modnetwork", "Initializing TCP/IP"); + tcpip_adapter_init(); + ESP_LOGD("modnetwork", "Initializing Event Loop"); + ESP_EXCEPTIONS( esp_event_loop_init(event_handler, NULL) ); + ESP_LOGD("modnetwork", "esp_event_loop_init done"); + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_LOGD("modnetwork", "Initializing WiFi"); + ESP_EXCEPTIONS( esp_wifi_init(&cfg) ); + ESP_EXCEPTIONS( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); + ESP_LOGD("modnetwork", "Initialized"); + ESP_EXCEPTIONS( esp_wifi_set_mode(0) ); + ESP_EXCEPTIONS( esp_wifi_start() ); + ESP_LOGD("modnetwork", "Started"); + initialized = 1; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_initialize_obj, esp_initialize); + +#if (WIFI_MODE_STA & WIFI_MODE_AP != WIFI_MODE_NULL || WIFI_MODE_STA | WIFI_MODE_AP != WIFI_MODE_APSTA) +#error WIFI_MODE_STA and WIFI_MODE_AP are supposed to be bitfields! +#endif + +STATIC mp_obj_t esp_active(size_t n_args, const mp_obj_t *args) { + + wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + wifi_mode_t mode; + ESP_EXCEPTIONS( esp_wifi_get_mode(&mode) ); + int bit = (self->if_id == WIFI_IF_STA) ? WIFI_MODE_STA : WIFI_MODE_AP; + + if (n_args > 1) { + bool active = mp_obj_is_true(args[1]); + mode = active ? (mode | bit) : (mode & ~bit); + ESP_EXCEPTIONS( esp_wifi_set_mode(mode) ); + } + + return (mode & bit) ? mp_const_true : mp_const_false; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_active_obj, 1, 2, esp_active); + +STATIC mp_obj_t esp_connect(size_t n_args, const mp_obj_t *args) { + + mp_uint_t len; + const char *p; + if (n_args > 1) { + memset(&wifi_sta_config, 0, sizeof(wifi_sta_config)); + p = mp_obj_str_get_data(args[1], &len); + memcpy(wifi_sta_config.sta.ssid, p, MIN(len, sizeof(wifi_sta_config.sta.ssid))); + p = (n_args > 2) ? mp_obj_str_get_data(args[2], &len) : ""; + memcpy(wifi_sta_config.sta.password, p, MIN(len, sizeof(wifi_sta_config.sta.password))); + ESP_EXCEPTIONS( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config) ); + } + MP_THREAD_GIL_EXIT(); + ESP_EXCEPTIONS( esp_wifi_connect() ); + MP_THREAD_GIL_ENTER(); + wifi_sta_connected = true; + + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_connect_obj, 1, 7, esp_connect); + +STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) { + wifi_sta_connected = false; + ESP_EXCEPTIONS( esp_wifi_disconnect() ); + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_disconnect_obj, esp_disconnect); + +STATIC mp_obj_t esp_status(mp_obj_t self_in) { + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_status_obj, esp_status); + +STATIC mp_obj_t esp_scan(mp_obj_t self_in) { + // check that STA mode is active + wifi_mode_t mode; + ESP_EXCEPTIONS(esp_wifi_get_mode(&mode)); + if ((mode & WIFI_MODE_STA) == 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "STA must be active")); + } + + mp_obj_t list = mp_obj_new_list(0, NULL); + wifi_scan_config_t config = { 0 }; + // XXX how do we scan hidden APs (and if we can scan them, are they really hidden?) + MP_THREAD_GIL_EXIT(); + esp_err_t status = esp_wifi_scan_start(&config, 1); + MP_THREAD_GIL_ENTER(); + if (status == 0) { + uint16_t count = 0; + ESP_EXCEPTIONS( esp_wifi_scan_get_ap_num(&count) ); + wifi_ap_record_t *wifi_ap_records = calloc(count, sizeof(wifi_ap_record_t)); + ESP_EXCEPTIONS( esp_wifi_scan_get_ap_records(&count, wifi_ap_records) ); + for (uint16_t i = 0; i < count; i++) { + mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL); + uint8_t *x = memchr(wifi_ap_records[i].ssid, 0, sizeof(wifi_ap_records[i].ssid)); + int ssid_len = x ? x - wifi_ap_records[i].ssid : sizeof(wifi_ap_records[i].ssid); + t->items[0] = mp_obj_new_bytes(wifi_ap_records[i].ssid, ssid_len); + t->items[1] = mp_obj_new_bytes(wifi_ap_records[i].bssid, sizeof(wifi_ap_records[i].bssid)); + t->items[2] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].primary); + t->items[3] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].rssi); + t->items[4] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].authmode); + t->items[5] = mp_const_false; // XXX hidden? + mp_obj_list_append(list, MP_OBJ_FROM_PTR(t)); + } + free(wifi_ap_records); + } + return list; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_scan_obj, esp_scan); + +STATIC mp_obj_t esp_isconnected(mp_obj_t self_in) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->if_id == WIFI_IF_STA) { + tcpip_adapter_ip_info_t info; + tcpip_adapter_get_ip_info(WIFI_IF_STA, &info); + return mp_obj_new_bool(info.ip.addr != 0); + } else { + wifi_sta_list_t sta; + esp_wifi_ap_get_sta_list(&sta); + return mp_obj_new_bool(sta.num != 0); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_isconnected_obj, esp_isconnected); + +STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + tcpip_adapter_ip_info_t info; + ip_addr_t dns_addr; + tcpip_adapter_get_ip_info(self->if_id, &info); + if (n_args == 1) { + // get + dns_addr = dns_getserver(0); + mp_obj_t tuple[4] = { + netutils_format_ipv4_addr((uint8_t*)&info.ip, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&info.netmask, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&info.gw, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&dns_addr, NETUTILS_BIG), + }; + return mp_obj_new_tuple(4, tuple); + } else { + // set + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[1], 4, &items); + netutils_parse_ipv4_addr(items[0], (void*)&info.ip, NETUTILS_BIG); + if (mp_obj_is_integer(items[1])) { + // allow numeric netmask, i.e.: + // 24 -> 255.255.255.0 + // 16 -> 255.255.0.0 + // etc... + uint32_t* m = (uint32_t*)&info.netmask; + *m = htonl(0xffffffff << (32 - mp_obj_get_int(items[1]))); + } else { + netutils_parse_ipv4_addr(items[1], (void*)&info.netmask, NETUTILS_BIG); + } + netutils_parse_ipv4_addr(items[2], (void*)&info.gw, NETUTILS_BIG); + netutils_parse_ipv4_addr(items[3], (void*)&dns_addr, NETUTILS_BIG); + // To set a static IP we have to disable DHCP first + if (self->if_id == WIFI_IF_STA) { + esp_err_t e = tcpip_adapter_dhcpc_stop(WIFI_IF_STA); + if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) _esp_exceptions(e); + ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(WIFI_IF_STA, &info)); + } else if (self->if_id == WIFI_IF_AP) { + esp_err_t e = tcpip_adapter_dhcps_stop(WIFI_IF_AP); + if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) _esp_exceptions(e); + ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(WIFI_IF_AP, &info)); + ESP_EXCEPTIONS(tcpip_adapter_dhcps_start(WIFI_IF_AP)); + } + return mp_const_none; + } +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj, 1, 2, esp_ifconfig); + +STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + if (n_args != 1 && kwargs->used != 0) { + mp_raise_TypeError("either pos or kw args are allowed"); + } + + wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + // get the config for the interface + wifi_config_t cfg; + ESP_EXCEPTIONS(esp_wifi_get_config(self->if_id, &cfg)); + + if (kwargs->used != 0) { + + for (size_t i = 0; i < kwargs->alloc; i++) { + if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) { + int req_if = -1; + + #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x) + switch ((uintptr_t)kwargs->table[i].key) { + case QS(MP_QSTR_mac): { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ); + if (bufinfo.len != 6) { + mp_raise_ValueError("invalid buffer length"); + } + ESP_EXCEPTIONS(esp_wifi_set_mac(self->if_id, bufinfo.buf)); + break; + } + case QS(MP_QSTR_essid): { + req_if = WIFI_IF_AP; + mp_uint_t len; + const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len); + len = MIN(len, sizeof(cfg.ap.ssid)); + memcpy(cfg.ap.ssid, s, len); + cfg.ap.ssid_len = len; + break; + } + case QS(MP_QSTR_hidden): { + req_if = WIFI_IF_AP; + cfg.ap.ssid_hidden = mp_obj_is_true(kwargs->table[i].value); + break; + } + case QS(MP_QSTR_authmode): { + req_if = WIFI_IF_AP; + cfg.ap.authmode = mp_obj_get_int(kwargs->table[i].value); + break; + } + case QS(MP_QSTR_password): { + req_if = WIFI_IF_AP; + mp_uint_t len; + const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len); + len = MIN(len, sizeof(cfg.ap.password) - 1); + memcpy(cfg.ap.password, s, len); + cfg.ap.password[len] = 0; + break; + } + case QS(MP_QSTR_channel): { + req_if = WIFI_IF_AP; + cfg.ap.channel = mp_obj_get_int(kwargs->table[i].value); + break; + } + default: + goto unknown; + } + #undef QS + + // We post-check interface requirements to save on code size + if (req_if >= 0) { + require_if(args[0], req_if); + } + } + } + + ESP_EXCEPTIONS(esp_wifi_set_config(self->if_id, &cfg)); + + return mp_const_none; + } + + // Get config + + if (n_args != 2) { + mp_raise_TypeError("can query only one param"); + } + + int req_if = -1; + mp_obj_t val; + + #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x) + switch ((uintptr_t)args[1]) { + case QS(MP_QSTR_mac): { + uint8_t mac[6]; + ESP_EXCEPTIONS(esp_wifi_get_mac(self->if_id, mac)); + return mp_obj_new_bytes(mac, sizeof(mac)); + } + case QS(MP_QSTR_essid): + req_if = WIFI_IF_AP; + val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len); + break; + case QS(MP_QSTR_hidden): + req_if = WIFI_IF_AP; + val = mp_obj_new_bool(cfg.ap.ssid_hidden); + break; + case QS(MP_QSTR_authmode): + req_if = WIFI_IF_AP; + val = MP_OBJ_NEW_SMALL_INT(cfg.ap.authmode); + break; + case QS(MP_QSTR_channel): + req_if = WIFI_IF_AP; + val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel); + break; + default: + goto unknown; + } + #undef QS + + // We post-check interface requirements to save on code size + if (req_if >= 0) { + require_if(args[0], req_if); + } + + return val; + +unknown: + mp_raise_ValueError("unknown config param"); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_config_obj, 1, esp_config); + +STATIC const mp_map_elem_t wlan_if_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_active), (mp_obj_t)&esp_active_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&esp_connect_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_disconnect), (mp_obj_t)&esp_disconnect_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_status), (mp_obj_t)&esp_status_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_scan), (mp_obj_t)&esp_scan_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_isconnected), (mp_obj_t)&esp_isconnected_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_config), (mp_obj_t)&esp_config_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ifconfig), (mp_obj_t)&esp_ifconfig_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(wlan_if_locals_dict, wlan_if_locals_dict_table); + +const mp_obj_type_t wlan_if_type = { + { &mp_type_type }, + .name = MP_QSTR_WLAN, + .locals_dict = (mp_obj_t)&wlan_if_locals_dict, +}; + +STATIC mp_obj_t esp_phy_mode(size_t n_args, const mp_obj_t *args) { + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_phy_mode_obj, 0, 1, esp_phy_mode); + + +STATIC const mp_map_elem_t mp_module_network_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_network) }, + { MP_OBJ_NEW_QSTR(MP_QSTR___init__), (mp_obj_t)&esp_initialize_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_WLAN), (mp_obj_t)&get_wlan_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_phy_mode), (mp_obj_t)&esp_phy_mode_obj }, + +#if MODNETWORK_INCLUDE_CONSTANTS + { MP_OBJ_NEW_QSTR(MP_QSTR_STA_IF), + MP_OBJ_NEW_SMALL_INT(WIFI_IF_STA)}, + { MP_OBJ_NEW_QSTR(MP_QSTR_AP_IF), + MP_OBJ_NEW_SMALL_INT(WIFI_IF_AP)}, + + { MP_OBJ_NEW_QSTR(MP_QSTR_MODE_11B), + MP_OBJ_NEW_SMALL_INT(WIFI_PROTOCOL_11B) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MODE_11G), + MP_OBJ_NEW_SMALL_INT(WIFI_PROTOCOL_11G) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MODE_11N), + MP_OBJ_NEW_SMALL_INT(WIFI_PROTOCOL_11N) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_AUTH_OPEN), + MP_OBJ_NEW_SMALL_INT(WIFI_AUTH_OPEN) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_AUTH_WEP), + MP_OBJ_NEW_SMALL_INT(WIFI_AUTH_WEP) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_AUTH_WPA_PSK), + MP_OBJ_NEW_SMALL_INT(WIFI_AUTH_WPA_PSK) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_AUTH_WPA2_PSK), + MP_OBJ_NEW_SMALL_INT(WIFI_AUTH_WPA2_PSK) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_AUTH_WPA_WPA2_PSK), + MP_OBJ_NEW_SMALL_INT(WIFI_AUTH_WPA_WPA2_PSK) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_AUTH_MAX), + MP_OBJ_NEW_SMALL_INT(WIFI_AUTH_MAX) }, +#endif +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals_table); + +const mp_obj_module_t mp_module_network = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_network_globals, +}; diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c new file mode 100644 index 0000000000..6ba61e874f --- /dev/null +++ b/ports/esp32/modsocket.c @@ -0,0 +1,570 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * and Mnemote Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016, 2017 Nick Moore @mnemote + * + * Based on extmod/modlwip.c + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Galen Hazelwood + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "py/runtime0.h" +#include "py/nlr.h" +#include "py/objlist.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "lib/netutils/netutils.h" +#include "tcpip_adapter.h" + +#include "lwip/sockets.h" +#include "lwip/netdb.h" +#include "lwip/ip4.h" +#include "esp_log.h" + +#define SOCKET_POLL_US (100000) + +typedef struct _socket_obj_t { + mp_obj_base_t base; + int fd; + uint8_t domain; + uint8_t type; + uint8_t proto; + unsigned int retries; +} socket_obj_t; + +void _socket_settimeout(socket_obj_t *sock, uint64_t timeout_ms); + +NORETURN static void exception_from_errno(int _errno) { + // Here we need to convert from lwip errno values to MicroPython's standard ones + if (_errno == EINPROGRESS) { + _errno = MP_EINPROGRESS; + } + mp_raise_OSError(_errno); +} + +void check_for_exceptions() { + mp_obj_t exc = MP_STATE_VM(mp_pending_exception); + if (exc != MP_OBJ_NULL) { + MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + nlr_raise(exc); + } +} + +STATIC mp_obj_t socket_close(const mp_obj_t arg0) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + if (self->fd >= 0) { + int ret = lwip_close_r(self->fd); + if (ret != 0) { + exception_from_errno(errno); + } + self->fd = -1; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); + +static int _socket_getaddrinfo2(const mp_obj_t host, const mp_obj_t portx, struct addrinfo **resp) { + const struct addrinfo hints = { + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM, + }; + + mp_obj_t port = portx; + if (MP_OBJ_IS_SMALL_INT(port)) { + // This is perverse, because lwip_getaddrinfo promptly converts it back to an int, but + // that's the API we have to work with ... + port = mp_obj_str_binary_op(MP_BINARY_OP_MODULO, mp_obj_new_str_via_qstr("%s", 2), port); + } + + const char *host_str = mp_obj_str_get_str(host); + const char *port_str = mp_obj_str_get_str(port); + + if (host_str[0] == '\0') { + // a host of "" is equivalent to the default/all-local IP address + host_str = "0.0.0.0"; + } + + MP_THREAD_GIL_EXIT(); + int res = lwip_getaddrinfo(host_str, port_str, &hints, resp); + MP_THREAD_GIL_ENTER(); + + return res; +} + +int _socket_getaddrinfo(const mp_obj_t addrtuple, struct addrinfo **resp) { + mp_uint_t len = 0; + mp_obj_t *elem; + mp_obj_get_array(addrtuple, &len, &elem); + if (len != 2) return -1; + return _socket_getaddrinfo2(elem[0], elem[1], resp); +} + +STATIC mp_obj_t socket_bind(const mp_obj_t arg0, const mp_obj_t arg1) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + struct addrinfo *res; + _socket_getaddrinfo(arg1, &res); + int r = lwip_bind_r(self->fd, res->ai_addr, res->ai_addrlen); + lwip_freeaddrinfo(res); + if (r < 0) exception_from_errno(errno); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind); + +STATIC mp_obj_t socket_listen(const mp_obj_t arg0, const mp_obj_t arg1) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + int backlog = mp_obj_get_int(arg1); + int r = lwip_listen_r(self->fd, backlog); + if (r < 0) exception_from_errno(errno); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen); + +STATIC mp_obj_t socket_accept(const mp_obj_t arg0) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + + struct sockaddr addr; + socklen_t addr_len = sizeof(addr); + + int new_fd = -1; + for (int i=0; i<=self->retries; i++) { + MP_THREAD_GIL_EXIT(); + new_fd = lwip_accept_r(self->fd, &addr, &addr_len); + MP_THREAD_GIL_ENTER(); + if (new_fd >= 0) break; + if (errno != EAGAIN) exception_from_errno(errno); + check_for_exceptions(); + } + if (new_fd < 0) mp_raise_OSError(MP_ETIMEDOUT); + + // create new socket object + socket_obj_t *sock = m_new_obj_with_finaliser(socket_obj_t); + sock->base.type = self->base.type; + sock->fd = new_fd; + sock->domain = self->domain; + sock->type = self->type; + sock->proto = self->proto; + _socket_settimeout(sock, UINT64_MAX); + + // make the return value + uint8_t *ip = (uint8_t*)&((struct sockaddr_in*)&addr)->sin_addr; + mp_uint_t port = lwip_ntohs(((struct sockaddr_in*)&addr)->sin_port); + mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL); + client->items[0] = sock; + client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); + + return client; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept); + +STATIC mp_obj_t socket_connect(const mp_obj_t arg0, const mp_obj_t arg1) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + struct addrinfo *res; + _socket_getaddrinfo(arg1, &res); + MP_THREAD_GIL_EXIT(); + int r = lwip_connect_r(self->fd, res->ai_addr, res->ai_addrlen); + MP_THREAD_GIL_ENTER(); + lwip_freeaddrinfo(res); + if (r != 0) { + exception_from_errno(errno); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect); + +STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { + (void)n_args; // always 4 + socket_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + int level = mp_obj_get_int(args[1]); + if (level != SOL_SOCKET) { + mp_raise_ValueError("unsupported level"); + } + + // only "int" arguments are supported at the moment + int opt = mp_obj_get_int(args[2]); + int val = mp_obj_get_int(args[3]); + int ret = lwip_setsockopt_r(self->fd, SOL_SOCKET, opt, &val, sizeof(int)); + + if (ret != 0) { + exception_from_errno(errno); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt); + +void _socket_settimeout(socket_obj_t *sock, uint64_t timeout_ms) { + // Rather than waiting for the entire timeout specified, we wait sock->retries times + // for SOCKET_POLL_US each, checking for a MicroPython interrupt between timeouts. + // with SOCKET_POLL_MS == 100ms, sock->retries allows for timeouts up to 13 years. + // if timeout_ms == UINT64_MAX, wait forever. + sock->retries = (timeout_ms == UINT64_MAX) ? UINT_MAX : timeout_ms * 1000 / SOCKET_POLL_US; + + struct timeval timeout = { + .tv_sec = 0, + .tv_usec = timeout_ms ? SOCKET_POLL_US : 0 + }; + lwip_setsockopt_r(sock->fd, SOL_SOCKET, SO_SNDTIMEO, (const void *)&timeout, sizeof(timeout)); + lwip_setsockopt_r(sock->fd, SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout)); + lwip_fcntl_r(sock->fd, F_SETFL, timeout_ms ? 0 : O_NONBLOCK); +} + +STATIC mp_obj_t socket_settimeout(const mp_obj_t arg0, const mp_obj_t arg1) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + if (arg1 == mp_const_none) _socket_settimeout(self, UINT64_MAX); + else _socket_settimeout(self, mp_obj_get_float(arg1) * 1000L); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout); + +STATIC mp_obj_t socket_setblocking(const mp_obj_t arg0, const mp_obj_t arg1) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + if (mp_obj_is_true(arg1)) _socket_settimeout(self, UINT64_MAX); + else _socket_settimeout(self, 0); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); + +mp_obj_t _socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in, + struct sockaddr *from, socklen_t *from_len) { + socket_obj_t *sock = MP_OBJ_TO_PTR(self_in); + size_t len = mp_obj_get_int(len_in); + vstr_t vstr; + vstr_init_len(&vstr, len); + + // XXX Would be nicer to use RTC to handle timeouts + for (int i=0; i<=sock->retries; i++) { + MP_THREAD_GIL_EXIT(); + int r = lwip_recvfrom_r(sock->fd, vstr.buf, len, 0, from, from_len); + MP_THREAD_GIL_ENTER(); + if (r >= 0) { vstr.len = r; return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } + if (errno != EWOULDBLOCK) exception_from_errno(errno); + check_for_exceptions(); + } + mp_raise_OSError(MP_ETIMEDOUT); +} + +STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) { + return _socket_recvfrom(self_in, len_in, NULL, NULL); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv); + +STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { + struct sockaddr from; + socklen_t fromlen = sizeof(from); + + mp_obj_t tuple[2]; + tuple[0] = _socket_recvfrom(self_in, len_in, &from, &fromlen); + + uint8_t *ip = (uint8_t*)&((struct sockaddr_in*)&from)->sin_addr; + mp_uint_t port = lwip_ntohs(((struct sockaddr_in*)&from)->sin_port); + tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); + + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recvfrom_obj, socket_recvfrom); + +int _socket_send(socket_obj_t *sock, const char *data, size_t datalen) { + int sentlen = 0; + for (int i=0; i<=sock->retries && sentlen < datalen; i++) { + MP_THREAD_GIL_EXIT(); + int r = lwip_write_r(sock->fd, data+sentlen, datalen-sentlen); + MP_THREAD_GIL_ENTER(); + if (r < 0 && errno != EWOULDBLOCK) exception_from_errno(errno); + if (r > 0) sentlen += r; + check_for_exceptions(); + } + if (sentlen == 0) mp_raise_OSError(MP_ETIMEDOUT); + return sentlen; +} + +STATIC mp_obj_t socket_send(const mp_obj_t arg0, const mp_obj_t arg1) { + socket_obj_t *sock = MP_OBJ_TO_PTR(arg0); + mp_uint_t datalen; + const char *data = mp_obj_str_get_data(arg1, &datalen); + int r = _socket_send(sock, data, datalen); + return mp_obj_new_int(r); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send); + +STATIC mp_obj_t socket_sendall(const mp_obj_t arg0, const mp_obj_t arg1) { + // XXX behaviour when nonblocking (see extmod/modlwip.c) + // XXX also timeout behaviour. + socket_obj_t *sock = MP_OBJ_TO_PTR(arg0); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg1, &bufinfo, MP_BUFFER_READ); + int r = _socket_send(sock, bufinfo.buf, bufinfo.len); + if (r < bufinfo.len) mp_raise_OSError(MP_ETIMEDOUT); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_sendall_obj, socket_sendall); + +STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) { + socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // get the buffer to send + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ); + + // create the destination address + struct sockaddr_in to; + to.sin_len = sizeof(to); + to.sin_family = AF_INET; + to.sin_port = lwip_htons(netutils_parse_inet_addr(addr_in, (uint8_t*)&to.sin_addr, NETUTILS_BIG)); + + // send the data + for (int i=0; i<=self->retries; i++) { + MP_THREAD_GIL_EXIT(); + int ret = lwip_sendto_r(self->fd, bufinfo.buf, bufinfo.len, 0, (struct sockaddr*)&to, sizeof(to)); + MP_THREAD_GIL_ENTER(); + if (ret > 0) return mp_obj_new_int_from_uint(ret); + if (ret == -1 && errno != EWOULDBLOCK) { + exception_from_errno(errno); + } + check_for_exceptions(); + } + mp_raise_OSError(MP_ETIMEDOUT); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(socket_sendto_obj, socket_sendto); + +STATIC mp_obj_t socket_fileno(const mp_obj_t arg0) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + return mp_obj_new_int(self->fd); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_fileno_obj, socket_fileno); + +STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) { + (void)n_args; + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 3, socket_makefile); + + +// XXX this can end up waiting a very long time if the content is dribbled in one character +// at a time, as the timeout resets each time a recvfrom succeeds ... this is probably not +// good behaviour. + +STATIC mp_uint_t socket_stream_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { + socket_obj_t *sock = self_in; + + // XXX Would be nicer to use RTC to handle timeouts + for (int i=0; i<=sock->retries; i++) { + MP_THREAD_GIL_EXIT(); + int r = lwip_recvfrom_r(sock->fd, buf, size, 0, NULL, NULL); + MP_THREAD_GIL_ENTER(); + if (r >= 0) return r; + if (r < 0 && errno != EWOULDBLOCK) { *errcode = errno; return MP_STREAM_ERROR; } + check_for_exceptions(); + } + *errcode = sock->retries == 0 ? MP_EWOULDBLOCK : MP_ETIMEDOUT; + return MP_STREAM_ERROR; +} + +STATIC mp_uint_t socket_stream_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { + socket_obj_t *sock = self_in; + for (int i=0; i<=sock->retries; i++) { + MP_THREAD_GIL_EXIT(); + int r = lwip_write_r(sock->fd, buf, size); + MP_THREAD_GIL_ENTER(); + if (r > 0) return r; + if (r < 0 && errno != EWOULDBLOCK) { *errcode = errno; return MP_STREAM_ERROR; } + check_for_exceptions(); + } + *errcode = sock->retries == 0 ? MP_EWOULDBLOCK : MP_ETIMEDOUT; + return MP_STREAM_ERROR; +} + +STATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + socket_obj_t * socket = self_in; + if (request == MP_STREAM_POLL) { + + fd_set rfds; FD_ZERO(&rfds); + fd_set wfds; FD_ZERO(&wfds); + fd_set efds; FD_ZERO(&efds); + struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 }; + if (arg & MP_STREAM_POLL_RD) FD_SET(socket->fd, &rfds); + if (arg & MP_STREAM_POLL_WR) FD_SET(socket->fd, &wfds); + if (arg & MP_STREAM_POLL_HUP) FD_SET(socket->fd, &efds); + + int r = select((socket->fd)+1, &rfds, &wfds, &efds, &timeout); + if (r < 0) { + *errcode = MP_EIO; + return MP_STREAM_ERROR; + } + + mp_uint_t ret = 0; + if (FD_ISSET(socket->fd, &rfds)) ret |= MP_STREAM_POLL_RD; + if (FD_ISSET(socket->fd, &wfds)) ret |= MP_STREAM_POLL_WR; + if (FD_ISSET(socket->fd, &efds)) ret |= MP_STREAM_POLL_HUP; + return ret; + } + + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; +} + +STATIC const mp_map_elem_t socket_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&socket_close_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&socket_close_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_bind), (mp_obj_t)&socket_bind_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_listen), (mp_obj_t)&socket_listen_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_accept), (mp_obj_t)&socket_accept_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&socket_connect_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&socket_send_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sendall), (mp_obj_t)&socket_sendall_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sendto), (mp_obj_t)&socket_sendto_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&socket_recv_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_recvfrom), (mp_obj_t)&socket_recvfrom_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_setsockopt), (mp_obj_t)&socket_setsockopt_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_settimeout), (mp_obj_t)&socket_settimeout_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_setblocking), (mp_obj_t)&socket_setblocking_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_makefile), (mp_obj_t)&socket_makefile_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_fileno), (mp_obj_t)&socket_fileno_obj }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&mp_stream_readinto_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj}, + { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj }, +}; +STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table); + +STATIC const mp_stream_p_t socket_stream_p = { + .read = socket_stream_read, + .write = socket_stream_write, + .ioctl = socket_stream_ioctl +}; + +STATIC const mp_obj_type_t socket_type = { + { &mp_type_type }, + .name = MP_QSTR_socket, + .protocol = &socket_stream_p, + .locals_dict = (mp_obj_t)&socket_locals_dict, +}; + +STATIC mp_obj_t get_socket(size_t n_args, const mp_obj_t *args) { + socket_obj_t *sock = m_new_obj_with_finaliser(socket_obj_t); + sock->base.type = &socket_type; + sock->domain = AF_INET; + sock->type = SOCK_STREAM; + sock->proto = 0; + if (n_args > 0) { + sock->domain = mp_obj_get_int(args[0]); + if (n_args > 1) { + sock->type = mp_obj_get_int(args[1]); + if (n_args > 2) { + sock->proto = mp_obj_get_int(args[2]); + } + } + } + + sock->fd = lwip_socket(sock->domain, sock->type, sock->proto); + if (sock->fd < 0) { + exception_from_errno(errno); + } + _socket_settimeout(sock, UINT64_MAX); + + return MP_OBJ_FROM_PTR(sock); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_socket_obj, 0, 3, get_socket); + +STATIC mp_obj_t esp_socket_getaddrinfo(const mp_obj_t host, const mp_obj_t port) { + struct addrinfo *res = NULL; + _socket_getaddrinfo2(host, port, &res); + mp_obj_t ret_list = mp_obj_new_list(0, NULL); + + for (struct addrinfo *resi = res; resi; resi = resi->ai_next) { + mp_obj_t addrinfo_objs[5] = { + mp_obj_new_int(resi->ai_family), + mp_obj_new_int(resi->ai_socktype), + mp_obj_new_int(resi->ai_protocol), + mp_obj_new_str(resi->ai_canonname, strlen(resi->ai_canonname)), + mp_const_none + }; + + if (resi->ai_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)resi->ai_addr; + // This looks odd, but it's really just a u32_t + ip4_addr_t ip4_addr = { .addr = addr->sin_addr.s_addr }; + char buf[16]; + ip4addr_ntoa_r(&ip4_addr, buf, sizeof(buf)); + mp_obj_t inaddr_objs[2] = { + mp_obj_new_str(buf, strlen(buf)), + mp_obj_new_int(ntohs(addr->sin_port)) + }; + addrinfo_objs[4] = mp_obj_new_tuple(2, inaddr_objs); + } + mp_obj_list_append(ret_list, mp_obj_new_tuple(5, addrinfo_objs)); + } + + if (res) lwip_freeaddrinfo(res); + return ret_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_socket_getaddrinfo_obj, esp_socket_getaddrinfo); + +STATIC mp_obj_t esp_socket_initialize() { + static int initialized = 0; + if (!initialized) { + ESP_LOGI("modsocket", "Initializing"); + tcpip_adapter_init(); + initialized = 1; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_socket_initialize_obj, esp_socket_initialize); + +STATIC const mp_map_elem_t mp_module_socket_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_usocket) }, + { MP_OBJ_NEW_QSTR(MP_QSTR___init__), (mp_obj_t)&esp_socket_initialize_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&get_socket_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_getaddrinfo), (mp_obj_t)&esp_socket_getaddrinfo_obj }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET), MP_OBJ_NEW_SMALL_INT(AF_INET) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET6), MP_OBJ_NEW_SMALL_INT(AF_INET6) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_STREAM), MP_OBJ_NEW_SMALL_INT(SOCK_STREAM) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_DGRAM), MP_OBJ_NEW_SMALL_INT(SOCK_DGRAM) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_RAW), MP_OBJ_NEW_SMALL_INT(SOCK_RAW) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_TCP), MP_OBJ_NEW_SMALL_INT(IPPROTO_TCP) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_UDP), MP_OBJ_NEW_SMALL_INT(IPPROTO_UDP) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SOL_SOCKET), MP_OBJ_NEW_SMALL_INT(SOL_SOCKET) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SO_REUSEADDR), MP_OBJ_NEW_SMALL_INT(SO_REUSEADDR) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_socket_globals, mp_module_socket_globals_table); + +const mp_obj_module_t mp_module_usocket = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_socket_globals, +}; diff --git a/ports/esp32/moduhashlib.c b/ports/esp32/moduhashlib.c new file mode 100644 index 0000000000..6f67aa7d9d --- /dev/null +++ b/ports/esp32/moduhashlib.c @@ -0,0 +1,142 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "py/runtime.h" + +#include "mbedtls/sha256.h" +#include "mbedtls/sha1.h" + +union sha_ctxs { + mbedtls_sha256_context sha256; + mbedtls_sha1_context sha1; +}; +typedef struct _mp_obj_hash_t { + mp_obj_base_t base; + union sha_ctxs state; +} mp_obj_hash_t; + +STATIC mp_obj_t sha256_update(mp_obj_t self_in, mp_obj_t arg); +STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg); + +STATIC mp_obj_t sha256_make_new(const mp_obj_type_t *type, + size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(union sha_ctxs)); + o->base.type = type; + mbedtls_sha256_init(&o->state.sha256); + if (n_args == 1) { + sha256_update(MP_OBJ_FROM_PTR(o), args[0]); + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t sha1_make_new(const mp_obj_type_t *type, + size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(union sha_ctxs)); + o->base.type = type; + mbedtls_sha1_init(&o->state.sha1); + if (n_args == 1) { + sha1_update(MP_OBJ_FROM_PTR(o), args[0]); + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t sha256_update(mp_obj_t self_in, mp_obj_t arg) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); + mbedtls_sha256_update(&self->state.sha256, bufinfo.buf, bufinfo.len); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(sha256_update_obj, sha256_update); + +STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); + mbedtls_sha1_update(&self->state.sha1, bufinfo.buf, bufinfo.len); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(sha1_update_obj, sha1_update); + +STATIC mp_obj_t sha256_digest(mp_obj_t self_in) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + vstr_t vstr; + vstr_init_len(&vstr, 32); + mbedtls_sha256_finish(&self->state.sha256, (unsigned char *)vstr.buf); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_1(sha256_digest_obj, sha256_digest); + +STATIC mp_obj_t sha1_digest(mp_obj_t self_in) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + vstr_t vstr; + vstr_init_len(&vstr, 20); + mbedtls_sha1_finish(&self->state.sha1, (unsigned char *)vstr.buf); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_1(sha1_digest_obj, sha1_digest); + +STATIC const mp_rom_map_elem_t sha256_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&sha256_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&sha256_digest_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(sha256_locals_dict, sha256_locals_dict_table); + +STATIC const mp_obj_type_t sha256_type = { + { &mp_type_type }, + .name = MP_QSTR_sha256, + .make_new = sha256_make_new, + .locals_dict = (void*)&sha256_locals_dict, +}; + +STATIC const mp_rom_map_elem_t sha1_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&sha1_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&sha1_digest_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(sha1_locals_dict, sha1_locals_dict_table); + +STATIC const mp_obj_type_t sha1_type = { + { &mp_type_type }, + .name = MP_QSTR_sha1, + .make_new = sha1_make_new, + .locals_dict = (void*)&sha1_locals_dict, +}; + +STATIC const mp_rom_map_elem_t mp_module_hashlib_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uhashlib) }, + { MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&sha256_type) }, + { MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&sha1_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_hashlib_globals, + mp_module_hashlib_globals_table); + +const mp_obj_module_t mp_module_uhashlib = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_hashlib_globals, +}; diff --git a/ports/esp32/modules/_boot.py b/ports/esp32/modules/_boot.py new file mode 100644 index 0000000000..bf40ea3a9f --- /dev/null +++ b/ports/esp32/modules/_boot.py @@ -0,0 +1,12 @@ +import gc +import uos +from flashbdev import bdev + +try: + if bdev: + uos.mount(bdev, '/') +except OSError: + import inisetup + vfs = inisetup.setup() + +gc.collect() diff --git a/ports/esp32/modules/apa106.py b/ports/esp32/modules/apa106.py new file mode 100644 index 0000000000..ef971d78ba --- /dev/null +++ b/ports/esp32/modules/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/ports/esp32/modules/dht.py b/ports/esp32/modules/dht.py new file mode 120000 index 0000000000..b6acf2853e --- /dev/null +++ b/ports/esp32/modules/dht.py @@ -0,0 +1 @@ +../../esp8266/modules/dht.py \ No newline at end of file diff --git a/ports/esp32/modules/ds18x20.py b/ports/esp32/modules/ds18x20.py new file mode 120000 index 0000000000..9721929a3f --- /dev/null +++ b/ports/esp32/modules/ds18x20.py @@ -0,0 +1 @@ +../../esp8266/modules/ds18x20.py \ No newline at end of file diff --git a/ports/esp32/modules/flashbdev.py b/ports/esp32/modules/flashbdev.py new file mode 100644 index 0000000000..935f5342fc --- /dev/null +++ b/ports/esp32/modules/flashbdev.py @@ -0,0 +1,34 @@ +import esp + +class FlashBdev: + + SEC_SIZE = 4096 + START_SEC = esp.flash_user_start() // SEC_SIZE + + def __init__(self, blocks): + self.blocks = blocks + + def readblocks(self, n, buf): + #print("readblocks(%s, %x(%d))" % (n, id(buf), len(buf))) + esp.flash_read((n + self.START_SEC) * self.SEC_SIZE, buf) + + def writeblocks(self, n, buf): + #print("writeblocks(%s, %x(%d))" % (n, id(buf), len(buf))) + #assert len(buf) <= self.SEC_SIZE, len(buf) + esp.flash_erase(n + self.START_SEC) + esp.flash_write((n + self.START_SEC) * self.SEC_SIZE, buf) + + def ioctl(self, op, arg): + #print("ioctl(%d, %r)" % (op, arg)) + if op == 4: # BP_IOCTL_SEC_COUNT + return self.blocks + if op == 5: # BP_IOCTL_SEC_SIZE + return self.SEC_SIZE + +size = esp.flash_size() +if size < 1024*1024: + # flash too small for a filesystem + bdev = None +else: + # for now we use a fixed size for the filesystem + bdev = FlashBdev(2048 * 1024 // FlashBdev.SEC_SIZE) diff --git a/ports/esp32/modules/inisetup.py b/ports/esp32/modules/inisetup.py new file mode 100644 index 0000000000..45bce82cc2 --- /dev/null +++ b/ports/esp32/modules/inisetup.py @@ -0,0 +1,38 @@ +import uos +from flashbdev import bdev + +def check_bootsec(): + buf = bytearray(bdev.SEC_SIZE) + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xff: + empty = False + break + if empty: + return True + fs_corrupted() + +def fs_corrupted(): + import time + while 1: + print("""\ +FAT filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""") + time.sleep(3) + +def setup(): + check_bootsec() + print("Performing initial setup") + uos.VfsFat.mkfs(bdev) + vfs = uos.VfsFat(bdev) + uos.mount(vfs, '/flash') + uos.chdir('/flash') + with open("boot.py", "w") as f: + f.write("""\ +# This file is executed on every boot (including wake-boot from deepsleep) +""") + return vfs diff --git a/ports/esp32/modules/neopixel.py b/ports/esp32/modules/neopixel.py new file mode 100644 index 0000000000..86c1586cdd --- /dev/null +++ b/ports/esp32/modules/neopixel.py @@ -0,0 +1,33 @@ +# NeoPixel driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from esp import neopixel_write + + +class NeoPixel: + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=0): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + self.timing = timing + + def __setitem__(self, index, val): + offset = index * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = val[i] + + def __getitem__(self, index): + offset = index * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] + for i in range(self.bpp)) + + def fill(self, color): + for i in range(self.n): + self[i] = color + + def write(self): + neopixel_write(self.pin, self.buf, self.timing) diff --git a/ports/esp32/modules/onewire.py b/ports/esp32/modules/onewire.py new file mode 120000 index 0000000000..091629488e --- /dev/null +++ b/ports/esp32/modules/onewire.py @@ -0,0 +1 @@ +../../esp8266/modules/onewire.py \ No newline at end of file diff --git a/ports/esp32/modules/upip.py b/ports/esp32/modules/upip.py new file mode 120000 index 0000000000..130eb69016 --- /dev/null +++ b/ports/esp32/modules/upip.py @@ -0,0 +1 @@ +../../../tools/upip.py \ No newline at end of file diff --git a/ports/esp32/modules/upip_utarfile.py b/ports/esp32/modules/upip_utarfile.py new file mode 120000 index 0000000000..d9653d6a60 --- /dev/null +++ b/ports/esp32/modules/upip_utarfile.py @@ -0,0 +1 @@ +../../../tools/upip_utarfile.py \ No newline at end of file diff --git a/ports/esp32/modules/upysh.py b/ports/esp32/modules/upysh.py new file mode 120000 index 0000000000..12d100c29c --- /dev/null +++ b/ports/esp32/modules/upysh.py @@ -0,0 +1 @@ +../../../../micropython-lib/upysh/upysh.py \ No newline at end of file diff --git a/ports/esp32/modules/urequests.py b/ports/esp32/modules/urequests.py new file mode 120000 index 0000000000..76661112e1 --- /dev/null +++ b/ports/esp32/modules/urequests.py @@ -0,0 +1 @@ +../../../../micropython-lib/urequests/urequests.py \ No newline at end of file diff --git a/ports/esp32/moduos.c b/ports/esp32/moduos.c new file mode 100644 index 0000000000..9f0e291a68 --- /dev/null +++ b/ports/esp32/moduos.c @@ -0,0 +1,128 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Josef Gajdusek + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "esp_system.h" + +#include "py/mpconfig.h" +#include "py/obj.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "py/mperrno.h" +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" +#include "genhdr/mpversion.h" + +extern const mp_obj_type_t mp_fat_vfs_type; + +STATIC const qstr os_uname_info_fields[] = { + MP_QSTR_sysname, MP_QSTR_nodename, + MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine +}; +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, MICROPY_PY_SYS_PLATFORM); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, MICROPY_PY_SYS_PLATFORM); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_release_obj, MICROPY_VERSION_STRING); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME); + +STATIC MP_DEFINE_ATTRTUPLE( + os_uname_info_obj, + os_uname_info_fields, + 5, + (mp_obj_t)&os_uname_info_sysname_obj, + (mp_obj_t)&os_uname_info_nodename_obj, + (mp_obj_t)&os_uname_info_release_obj, + (mp_obj_t)&os_uname_info_version_obj, + (mp_obj_t)&os_uname_info_machine_obj +); + +STATIC mp_obj_t os_uname(void) { + return (mp_obj_t)&os_uname_info_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname); + +STATIC mp_obj_t os_urandom(mp_obj_t num) { + mp_int_t n = mp_obj_get_int(num); + vstr_t vstr; + vstr_init_len(&vstr, n); + uint32_t r = 0; + for (int i = 0; i < n; i++) { + if ((i & 3) == 0) { + r = esp_random(); // returns 32-bit hardware random number + } + vstr.buf[i] = r; + r >>= 8; + } + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); + +#if MICROPY_PY_OS_DUPTERM +STATIC mp_obj_t os_dupterm_notify(mp_obj_t obj_in) { + (void)obj_in; + mp_hal_signal_dupterm_input(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_dupterm_notify_obj, os_dupterm_notify); +#endif + +STATIC const mp_rom_map_elem_t os_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, + { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) }, + { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) }, + #if MICROPY_PY_OS_DUPTERM + { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) }, + { MP_ROM_QSTR(MP_QSTR_dupterm_notify), MP_ROM_PTR(&os_dupterm_notify_obj) }, + #endif + #if MICROPY_VFS + { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mp_vfs_rename_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) }, + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) }, + #if MICROPY_VFS_FAT + { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, + #endif + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table); + +const mp_obj_module_t uos_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&os_module_globals, +}; diff --git a/ports/esp32/modutime.c b/ports/esp32/modutime.c new file mode 100644 index 0000000000..f037faad95 --- /dev/null +++ b/ports/esp32/modutime.c @@ -0,0 +1,61 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "extmod/utime_mphal.h" + +STATIC mp_obj_t time_time(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return mp_obj_new_int(tv.tv_sec); +} +MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); + +STATIC const mp_rom_map_elem_t time_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, + + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table); + +const mp_obj_module_t utime_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&time_module_globals, +}; diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h new file mode 100644 index 0000000000..2c32593244 --- /dev/null +++ b/ports/esp32/mpconfigport.h @@ -0,0 +1,248 @@ +// Options to control how MicroPython is built for this port, +// overriding defaults in py/mpconfig.h. + +#include +#include +#include "rom/ets_sys.h" + +// object representation and NLR handling +#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A) +#define MICROPY_NLR_SETJMP (1) + +// memory allocation policies +#define MICROPY_ALLOC_PATH_MAX (128) + +// emitters +#define MICROPY_PERSISTENT_CODE_LOAD (1) + +// compiler configuration +#define MICROPY_COMP_MODULE_CONST (1) +#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1) + +// optimisations +#define MICROPY_OPT_COMPUTED_GOTO (1) +#define MICROPY_OPT_MPZ_BITWISE (1) + +// Python internal features +#define MICROPY_READER_VFS (1) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_ENABLE_FINALISER (1) +#define MICROPY_STACK_CHECK (1) +#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) +#define MICROPY_KBD_EXCEPTION (1) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_REPL_EMACS_KEYS (1) +#define MICROPY_REPL_AUTO_INDENT (1) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_ENABLE_SOURCE_LINE (1) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL) +#define MICROPY_WARNINGS (1) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) +#define MICROPY_PY_BUILTINS_COMPLEX (1) +#define MICROPY_CPYTHON_COMPAT (1) +#define MICROPY_STREAMS_NON_BLOCK (1) +#define MICROPY_STREAMS_POSIX_API (1) +#define MICROPY_MODULE_BUILTIN_INIT (1) +#define MICROPY_MODULE_WEAK_LINKS (1) +#define MICROPY_MODULE_FROZEN_STR (0) +#define MICROPY_MODULE_FROZEN_MPY (1) +#define MICROPY_QSTR_EXTRA_POOL mp_qstr_frozen_const_pool +#define MICROPY_CAN_OVERRIDE_BUILTINS (1) +#define MICROPY_USE_INTERNAL_ERRNO (1) +#define MICROPY_USE_INTERNAL_PRINTF (0) // ESP32 SDK requires its own printf +#define MICROPY_ENABLE_SCHEDULER (1) +#define MICROPY_SCHEDULER_DEPTH (8) +#define MICROPY_VFS (1) +#define MICROPY_VFS_FAT (1) + +// control over Python builtins +#define MICROPY_PY_FUNCTION_ATTRS (1) +#define MICROPY_PY_STR_BYTES_CMP_WARN (1) +#define MICROPY_PY_BUILTINS_STR_UNICODE (1) +#define MICROPY_PY_BUILTINS_STR_CENTER (1) +#define MICROPY_PY_BUILTINS_STR_PARTITION (1) +#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1) +#define MICROPY_PY_BUILTINS_BYTEARRAY (1) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (1) +#define MICROPY_PY_BUILTINS_SET (1) +#define MICROPY_PY_BUILTINS_SLICE (1) +#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) +#define MICROPY_PY_BUILTINS_FROZENSET (1) +#define MICROPY_PY_BUILTINS_PROPERTY (1) +#define MICROPY_PY_BUILTINS_RANGE_ATTRS (1) +#define MICROPY_PY_BUILTINS_TIMEOUTERROR (1) +#define MICROPY_PY_ALL_SPECIAL_METHODS (1) +#define MICROPY_PY_BUILTINS_COMPILE (1) +#define MICROPY_PY_BUILTINS_ENUMERATE (1) +#define MICROPY_PY_BUILTINS_EXECFILE (1) +#define MICROPY_PY_BUILTINS_FILTER (1) +#define MICROPY_PY_BUILTINS_REVERSED (1) +#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1) +#define MICROPY_PY_BUILTINS_INPUT (1) +#define MICROPY_PY_BUILTINS_MIN_MAX (1) +#define MICROPY_PY_BUILTINS_POW3 (1) +#define MICROPY_PY_BUILTINS_HELP (1) +#define MICROPY_PY_BUILTINS_HELP_TEXT esp32_help_text +#define MICROPY_PY_BUILTINS_HELP_MODULES (1) +#define MICROPY_PY___FILE__ (1) +#define MICROPY_PY_MICROPYTHON_MEM_INFO (1) +#define MICROPY_PY_ARRAY (1) +#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) +#define MICROPY_PY_ATTRTUPLE (1) +#define MICROPY_PY_COLLECTIONS (1) +#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) +#define MICROPY_PY_MATH (1) +#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) +#define MICROPY_PY_CMATH (1) +#define MICROPY_PY_GC (1) +#define MICROPY_PY_IO (1) +#define MICROPY_PY_IO_FILEIO (1) +#define MICROPY_PY_IO_BYTESIO (1) +#define MICROPY_PY_IO_BUFFEREDWRITER (1) +#define MICROPY_PY_STRUCT (1) +#define MICROPY_PY_SYS (1) +#define MICROPY_PY_SYS_MAXSIZE (1) +#define MICROPY_PY_SYS_MODULES (1) +#define MICROPY_PY_SYS_EXIT (1) +#define MICROPY_PY_SYS_STDFILES (1) +#define MICROPY_PY_SYS_STDIO_BUFFER (1) +#define MICROPY_PY_UERRNO (1) +#define MICROPY_PY_USELECT (1) +#define MICROPY_PY_UTIME_MP_HAL (1) +#define MICROPY_PY_THREAD (1) +#define MICROPY_PY_THREAD_GIL (1) +#define MICROPY_PY_THREAD_GIL_VM_DIVISOR (32) + +// extended modules +#define MICROPY_PY_UCTYPES (1) +#define MICROPY_PY_UZLIB (1) +#define MICROPY_PY_UJSON (1) +#define MICROPY_PY_URE (1) +#define MICROPY_PY_UHEAPQ (1) +#define MICROPY_PY_UTIMEQ (1) +#define MICROPY_PY_UHASHLIB (0) // We use the ESP32 version +#define MICROPY_PY_UHASHLIB_SHA1 (MICROPY_PY_USSL && MICROPY_SSL_AXTLS) +#define MICROPY_PY_UBINASCII (1) +#define MICROPY_PY_UBINASCII_CRC32 (1) +#define MICROPY_PY_URANDOM (1) +#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) +#define MICROPY_PY_MACHINE (1) +#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new +#define MICROPY_PY_MACHINE_PULSE (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_SPI (1) +#define MICROPY_PY_MACHINE_SPI_MSB (0) +#define MICROPY_PY_MACHINE_SPI_LSB (1) +#define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hw_spi_make_new +#define MICROPY_PY_MACHINE_SPI_MIN_DELAY (0) +#define MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE (ets_get_cpu_frequency() * 1000000 / 200) // roughly +#define MICROPY_PY_USSL (1) +#define MICROPY_SSL_MBEDTLS (1) +#define MICROPY_PY_WEBSOCKET (0) +#define MICROPY_PY_FRAMEBUF (1) + +// fatfs configuration +#define MICROPY_FATFS_ENABLE_LFN (1) +#define MICROPY_FATFS_RPATH (2) +#define MICROPY_FATFS_MAX_SS (4096) +#define MICROPY_FATFS_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ +#define mp_type_fileio fatfs_type_fileio +#define mp_type_textio fatfs_type_textio + +// use vfs's functions for import stat and builtin open +#define mp_import_stat mp_vfs_import_stat +#define mp_builtin_open mp_vfs_open +#define mp_builtin_open_obj mp_vfs_open_obj + +// extra built in names to add to the global namespace +#define MICROPY_PORT_BUILTINS \ + { MP_OBJ_NEW_QSTR(MP_QSTR_input), (mp_obj_t)&mp_builtin_input_obj }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj }, + +// extra built in modules to add to the list of known ones +extern const struct _mp_obj_module_t esp_module; +extern const struct _mp_obj_module_t utime_module; +extern const struct _mp_obj_module_t uos_module; +extern const struct _mp_obj_module_t mp_module_usocket; +extern const struct _mp_obj_module_t mp_module_machine; +extern const struct _mp_obj_module_t mp_module_network; +extern const struct _mp_obj_module_t mp_module_onewire; + +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_OBJ_NEW_QSTR(MP_QSTR_esp), (mp_obj_t)&esp_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_utime), (mp_obj_t)&utime_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&uos_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_usocket), (mp_obj_t)&mp_module_usocket }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&mp_module_machine }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_network), (mp_obj_t)&mp_module_network }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR__onewire), (mp_obj_t)&mp_module_onewire }, \ + +#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ + { MP_OBJ_NEW_QSTR(MP_QSTR_binascii), (mp_obj_t)&mp_module_ubinascii }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_collections), (mp_obj_t)&mp_module_collections }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_errno), (mp_obj_t)&mp_module_uerrno }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_hashlib), (mp_obj_t)&mp_module_uhashlib }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_heapq), (mp_obj_t)&mp_module_uheapq }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_io), (mp_obj_t)&mp_module_io }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_json), (mp_obj_t)&mp_module_ujson }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&uos_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_random), (mp_obj_t)&mp_module_urandom }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_re), (mp_obj_t)&mp_module_ure }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_select), (mp_obj_t)&mp_module_uselect }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&mp_module_usocket }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_ssl), (mp_obj_t)&mp_module_ussl }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&mp_module_ustruct }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&utime_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_zlib), (mp_obj_t)&mp_module_uzlib }, \ + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[8]; \ + mp_obj_t machine_pin_irq_handler[40]; \ + +// type definitions for the specific machine + +#define BYTES_PER_WORD (4) +#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p))) +#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) +#define MP_SSIZE_MAX (0x7fffffff) + +// Note: these "critical nested" macros do not ensure cross-CPU exclusion, +// the only disable interrupts on the current CPU. To full manage exclusion +// one should use portENTER_CRITICAL/portEXIT_CRITICAL instead. +#include "freertos/FreeRTOS.h" +#define MICROPY_BEGIN_ATOMIC_SECTION() portENTER_CRITICAL_NESTED() +#define MICROPY_END_ATOMIC_SECTION(state) portEXIT_CRITICAL_NESTED(state) + +#if MICROPY_PY_THREAD +#define MICROPY_EVENT_POLL_HOOK \ + do { \ + extern void mp_handle_pending(void); \ + mp_handle_pending(); \ + MP_THREAD_GIL_EXIT(); \ + MP_THREAD_GIL_ENTER(); \ + } while (0); +#else +#define MICROPY_EVENT_POLL_HOOK \ + do { \ + extern void mp_handle_pending(void); \ + mp_handle_pending(); \ + asm("waiti 0"); \ + } while (0); +#endif + +#define UINT_FMT "%u" +#define INT_FMT "%d" + +typedef int32_t mp_int_t; // must be pointer size +typedef uint32_t mp_uint_t; // must be pointer size +typedef long mp_off_t; +// ssize_t, off_t as required by POSIX-signatured functions in stream.h +#include + +// board specifics + +#define MICROPY_HW_BOARD_NAME "ESP32 module" +#define MICROPY_HW_MCU_NAME "ESP32" +#define MICROPY_PY_SYS_PLATFORM "esp32" diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c new file mode 100644 index 0000000000..e588fc65a1 --- /dev/null +++ b/ports/esp32/mphalport.c @@ -0,0 +1,139 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "rom/uart.h" + +#include "py/obj.h" +#include "py/mpstate.h" +#include "py/mphal.h" +#include "extmod/misc.h" +#include "lib/utils/pyexec.h" + +STATIC uint8_t stdin_ringbuf_array[256]; +ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array)}; + +int mp_hal_stdin_rx_chr(void) { + for (;;) { + int c = ringbuf_get(&stdin_ringbuf); + if (c != -1) { + return c; + } + MICROPY_EVENT_POLL_HOOK + vTaskDelay(1); + } +} + +void mp_hal_stdout_tx_char(char c) { + uart_tx_one_char(c); + //mp_uos_dupterm_tx_strn(&c, 1); +} + +void mp_hal_stdout_tx_str(const char *str) { + MP_THREAD_GIL_EXIT(); + while (*str) { + mp_hal_stdout_tx_char(*str++); + } + MP_THREAD_GIL_ENTER(); +} + +void mp_hal_stdout_tx_strn(const char *str, uint32_t len) { + MP_THREAD_GIL_EXIT(); + while (len--) { + mp_hal_stdout_tx_char(*str++); + } + MP_THREAD_GIL_ENTER(); +} + +void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) { + MP_THREAD_GIL_EXIT(); + while (len--) { + if (*str == '\n') { + mp_hal_stdout_tx_char('\r'); + } + mp_hal_stdout_tx_char(*str++); + } + MP_THREAD_GIL_ENTER(); +} + +uint32_t mp_hal_ticks_ms(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +uint32_t mp_hal_ticks_us(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000000 + tv.tv_usec; +} + +void mp_hal_delay_ms(uint32_t ms) { + struct timeval tv_start; + struct timeval tv_end; + uint64_t dt; + gettimeofday(&tv_start, NULL); + for (;;) { + gettimeofday(&tv_end, NULL); + dt = (tv_end.tv_sec - tv_start.tv_sec) * 1000 + (tv_end.tv_usec - tv_start.tv_usec) / 1000; + if (dt + portTICK_PERIOD_MS >= ms) { + // doing a vTaskDelay would take us beyound requested delay time + break; + } + MICROPY_EVENT_POLL_HOOK + vTaskDelay(1); + } + if (dt < ms) { + // do the remaining delay accurately + ets_delay_us((ms - dt) * 1000); + } +} + +void mp_hal_delay_us(uint32_t us) { + ets_delay_us(us); +} + +// this function could do with improvements (eg use ets_delay_us) +void mp_hal_delay_us_fast(uint32_t us) { + uint32_t delay = ets_get_cpu_frequency() / 19; + while (--us) { + for (volatile uint32_t i = delay; i; --i) { + } + } +} + +/* +extern int mp_stream_errno; +int *__errno() { + return &mp_stream_errno; +} +*/ diff --git a/ports/esp32/mphalport.h b/ports/esp32/mphalport.h new file mode 100644 index 0000000000..8a0f1dc8b0 --- /dev/null +++ b/ports/esp32/mphalport.h @@ -0,0 +1,83 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef INCLUDED_MPHALPORT_H +#define INCLUDED_MPHALPORT_H + +#include "py/ringbuf.h" +#include "lib/utils/interrupt_char.h" + +extern ringbuf_t stdin_ringbuf; + +uint32_t mp_hal_ticks_us(void); +__attribute__((always_inline)) static inline uint32_t mp_hal_ticks_cpu(void) { + uint32_t ccount; + __asm__ __volatile__("rsr %0,ccount":"=a" (ccount)); + return ccount; +} + +void mp_hal_delay_us(uint32_t); +void mp_hal_delay_us_fast(uint32_t); +void mp_hal_set_interrupt_char(int c); +uint32_t mp_hal_get_cpu_freq(void); + +#define mp_hal_quiet_timing_enter() MICROPY_BEGIN_ATOMIC_SECTION() +#define mp_hal_quiet_timing_exit(irq_state) MICROPY_END_ATOMIC_SECTION(irq_state) + +// C-level pin HAL +#include "py/obj.h" +#include "driver/gpio.h" +#define MP_HAL_PIN_FMT "%u" +#define mp_hal_pin_obj_t gpio_num_t +mp_hal_pin_obj_t machine_pin_get_id(mp_obj_t pin_in); +#define mp_hal_get_pin_obj(o) machine_pin_get_id(o) +#define mp_obj_get_pin(o) machine_pin_get_id(o) // legacy name; only to support esp8266/modonewire +#define mp_hal_pin_name(p) (p) +static inline void mp_hal_pin_input(mp_hal_pin_obj_t pin) { + gpio_set_direction(pin, GPIO_MODE_INPUT); +} +static inline void mp_hal_pin_output(mp_hal_pin_obj_t pin) { + gpio_set_direction(pin, GPIO_MODE_INPUT_OUTPUT); +} +static inline void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin) { + gpio_set_direction(pin, GPIO_MODE_INPUT_OUTPUT_OD); +} +static inline void mp_hal_pin_od_low(mp_hal_pin_obj_t pin) { + gpio_set_level(pin, 0); +} +static inline void mp_hal_pin_od_high(mp_hal_pin_obj_t pin) { + gpio_set_level(pin, 1); +} +static inline int mp_hal_pin_read(mp_hal_pin_obj_t pin) { + return gpio_get_level(pin); +} +static inline void mp_hal_pin_write(mp_hal_pin_obj_t pin, int v) { + gpio_set_level(pin, v); +} + +#endif // INCLUDED_MPHALPORT_H diff --git a/ports/esp32/mpthreadport.c b/ports/esp32/mpthreadport.c new file mode 100644 index 0000000000..76d9431c03 --- /dev/null +++ b/ports/esp32/mpthreadport.c @@ -0,0 +1,226 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + * Copyright (c) 2017 Pycom Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "stdio.h" + +#include "py/mpconfig.h" +#include "py/mpstate.h" +#include "py/gc.h" +#include "py/mpthread.h" +#include "mpthreadport.h" + +#include "esp_task.h" + +#if MICROPY_PY_THREAD + +#define MP_THREAD_MIN_STACK_SIZE (4 * 1024) +#define MP_THREAD_DEFAULT_STACK_SIZE (MP_THREAD_MIN_STACK_SIZE + 1024) +#define MP_THREAD_PRIORITY (ESP_TASK_PRIO_MIN + 1) + +// this structure forms a linked list, one node per active thread +typedef struct _thread_t { + TaskHandle_t id; // system id of thread + int ready; // whether the thread is ready and running + void *arg; // thread Python args, a GC root pointer + void *stack; // pointer to the stack + StaticTask_t *tcb; // pointer to the Task Control Block + size_t stack_len; // number of words in the stack + struct _thread_t *next; +} thread_t; + +// the mutex controls access to the linked list +STATIC mp_thread_mutex_t thread_mutex; +STATIC thread_t thread_entry0; +STATIC thread_t *thread; // root pointer, handled by mp_thread_gc_others + +void mp_thread_init(void *stack, uint32_t stack_len) { + mp_thread_set_state(&mp_state_ctx.thread); + // create the first entry in the linked list of all threads + thread = &thread_entry0; + thread->id = xTaskGetCurrentTaskHandle(); + thread->ready = 1; + thread->arg = NULL; + thread->stack = stack; + thread->stack_len = stack_len; + thread->next = NULL; + mp_thread_mutex_init(&thread_mutex); +} + +void mp_thread_gc_others(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + for (thread_t *th = thread; th != NULL; th = th->next) { + gc_collect_root((void**)&th, 1); + gc_collect_root(&th->arg, 1); // probably not needed + if (th->id == xTaskGetCurrentTaskHandle()) { + continue; + } + if (!th->ready) { + continue; + } + gc_collect_root(th->stack, th->stack_len); // probably not needed + } + mp_thread_mutex_unlock(&thread_mutex); +} + +mp_state_thread_t *mp_thread_get_state(void) { + return pvTaskGetThreadLocalStoragePointer(NULL, 1); +} + +void mp_thread_set_state(void *state) { + vTaskSetThreadLocalStoragePointer(NULL, 1, state); +} + +void mp_thread_start(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + for (thread_t *th = thread; th != NULL; th = th->next) { + if (th->id == xTaskGetCurrentTaskHandle()) { + th->ready = 1; + break; + } + } + mp_thread_mutex_unlock(&thread_mutex); +} + +STATIC void *(*ext_thread_entry)(void*) = NULL; + +STATIC void freertos_entry(void *arg) { + if (ext_thread_entry) { + ext_thread_entry(arg); + } + vTaskDelete(NULL); + for (;;); +} + +void mp_thread_create_ex(void *(*entry)(void*), void *arg, size_t *stack_size, int priority, char *name) { + // store thread entry function into a global variable so we can access it + ext_thread_entry = entry; + + if (*stack_size == 0) { + *stack_size = MP_THREAD_DEFAULT_STACK_SIZE; // default stack size + } else if (*stack_size < MP_THREAD_MIN_STACK_SIZE) { + *stack_size = MP_THREAD_MIN_STACK_SIZE; // minimum stack size + } + + // allocate TCB, stack and linked-list node (must be outside thread_mutex lock) + StaticTask_t *tcb = m_new(StaticTask_t, 1); + StackType_t *stack = m_new(StackType_t, *stack_size / sizeof(StackType_t)); + thread_t *th = m_new_obj(thread_t); + + mp_thread_mutex_lock(&thread_mutex, 1); + + // create thread + TaskHandle_t id = xTaskCreateStaticPinnedToCore(freertos_entry, name, *stack_size / sizeof(StackType_t), arg, priority, stack, tcb, 0); + if (id == NULL) { + mp_thread_mutex_unlock(&thread_mutex); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread")); + } + + // adjust the stack_size to provide room to recover from hitting the limit + *stack_size -= 1024; + + // add thread to linked list of all threads + th->id = id; + th->ready = 0; + th->arg = arg; + th->stack = stack; + th->tcb = tcb; + th->stack_len = *stack_size / sizeof(StackType_t); + th->next = thread; + thread = th; + + mp_thread_mutex_unlock(&thread_mutex); +} + +void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) { + mp_thread_create_ex(entry, arg, stack_size, MP_THREAD_PRIORITY, "mp_thread"); +} + +void mp_thread_finish(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + for (thread_t *th = thread; th != NULL; th = th->next) { + if (th->id == xTaskGetCurrentTaskHandle()) { + th->ready = 0; + break; + } + } + mp_thread_mutex_unlock(&thread_mutex); +} + +void vPortCleanUpTCB(void *tcb) { + thread_t *prev = NULL; + mp_thread_mutex_lock(&thread_mutex, 1); + for (thread_t *th = thread; th != NULL; prev = th, th = th->next) { + // unlink the node from the list + if (th->tcb == tcb) { + if (prev != NULL) { + prev->next = th->next; + } else { + // move the start pointer + thread = th->next; + } + // explicitly release all its memory + m_del(StaticTask_t, th->tcb, 1); + m_del(StackType_t, th->stack, th->stack_len); + m_del(thread_t, th, 1); + break; + } + } + mp_thread_mutex_unlock(&thread_mutex); +} + +void mp_thread_mutex_init(mp_thread_mutex_t *mutex) { + mutex->handle = xSemaphoreCreateMutexStatic(&mutex->buffer); +} + +int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) { + return (pdTRUE == xSemaphoreTake(mutex->handle, wait ? portMAX_DELAY : 0)); +} + +void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) { + xSemaphoreGive(mutex->handle); +} + +void mp_thread_deinit(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + for (thread_t *th = thread; th != NULL; th = th->next) { + // don't delete the current task + if (th->id == xTaskGetCurrentTaskHandle()) { + continue; + } + vTaskDelete(th->id); + } + mp_thread_mutex_unlock(&thread_mutex); + // allow FreeRTOS to clean-up the threads + vTaskDelay(2); +} + +#else + +void vPortCleanUpTCB(void *tcb) { +} + +#endif // MICROPY_PY_THREAD diff --git a/ports/esp32/mpthreadport.h b/ports/esp32/mpthreadport.h new file mode 100644 index 0000000000..54e35d61c3 --- /dev/null +++ b/ports/esp32/mpthreadport.h @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + * Copyright (c) 2017 Pycom Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_ESP32_MPTHREADPORT_H +#define MICROPY_INCLUDED_ESP32_MPTHREADPORT_H + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/queue.h" + +typedef struct _mp_thread_mutex_t { + SemaphoreHandle_t handle; + StaticSemaphore_t buffer; +} mp_thread_mutex_t; + +void mp_thread_init(void *stack, uint32_t stack_len); +void mp_thread_gc_others(void); +void mp_thread_deinit(void); + +#endif // MICROPY_INCLUDED_ESP32_MPTHREADPORT_H diff --git a/ports/esp32/qstrdefsport.h b/ports/esp32/qstrdefsport.h new file mode 100644 index 0000000000..ff6c2cc426 --- /dev/null +++ b/ports/esp32/qstrdefsport.h @@ -0,0 +1,30 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// qstrs specific to this port, only needed if they aren't auto-generated + +// Entries for sys.path +Q(/lib) diff --git a/ports/esp32/sdkconfig.h b/ports/esp32/sdkconfig.h new file mode 100644 index 0000000000..ce254c0e6d --- /dev/null +++ b/ports/esp32/sdkconfig.h @@ -0,0 +1,162 @@ +#define CONFIG_TRACEMEM_RESERVE_DRAM 0x0 +#define CONFIG_BT_RESERVE_DRAM 0x0 +#define CONFIG_ULP_COPROC_RESERVE_MEM 0 +#define CONFIG_PHY_DATA_OFFSET 0xf000 +#define CONFIG_APP_OFFSET 0x10000 + +#define CONFIG_SPI_FLASH_ROM_DRIVER_PATCH 1 +#define CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS 1 +#define CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS 4 + +#define CONFIG_TCPIP_TASK_STACK_SIZE 2560 + +#define CONFIG_ESP32_APPTRACE_DEST_NONE 1 +#define CONFIG_ESP32_PHY_MAX_TX_POWER 20 +#define CONFIG_ESP32_PANIC_PRINT_REBOOT 1 +#define CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC 1 +#define CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 1 +#define CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ 240 +#define CONFIG_ESP32_DEFAULT_CPU_FREQ_240 1 +#define CONFIG_ESP32_DEBUG_OCDAWARE 1 +#define CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY 0 +#define CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE 1 +#define CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE 1 +#define CONFIG_ESP32_WIFI_AMPDU_ENABLED 1 +#define CONFIG_ESP32_WIFI_NVS_ENABLED 1 +#define CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM 10 +#define CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM 0 +#define CONFIG_ESP32_WIFI_TX_BUFFER_TYPE 1 +#define CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER 1 +#define CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM 32 +#define CONFIG_ESP32_WIFI_RX_BA_WIN 6 +#define CONFIG_ESP32_WIFI_TX_BA_WIN 6 +#define CONFIG_ESP32_XTAL_FREQ_AUTO 1 +#define CONFIG_ESP32_XTAL_FREQ 0 +#define CONFIG_ESP32_RTC_CLK_CAL_CYCLES 1024 +#define CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT 5 +#define CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT 2048 + +#define CONFIG_FOUR_MAC_ADDRESS_FROM_EFUSE 1 +#define CONFIG_DMA_RX_BUF_NUM 10 +#define CONFIG_DMA_TX_BUF_NUM 10 +#define CONFIG_EMAC_TASK_PRIORITY 20 + +#define CONFIG_INT_WDT 1 +#define CONFIG_INT_WDT_TIMEOUT_MS 300 +#define CONFIG_INT_WDT_CHECK_CPU1 0 +#define CONFIG_TASK_WDT 1 +#define CONFIG_TASK_WDT_TIMEOUT_S 5 +#define CONFIG_TASK_WDT_CHECK_IDLE_TASK 0 +#define CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1 0 + +#define CONFIG_FREERTOS_UNICORE 1 +#define CONFIG_FREERTOS_CORETIMER_0 1 +#define CONFIG_FREERTOS_HZ 100 +#define CONFIG_FREERTOS_ASSERT_FAIL_ABORT 1 +#define CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION 1 +#define CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE 1 +#define CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS 2 +#define CONFIG_FREERTOS_IDLE_TASK_STACKSIZE 1024 +#define CONFIG_FREERTOS_ISR_STACKSIZE 1536 +#define CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG 1 +#define CONFIG_FREERTOS_MAX_TASK_NAME_LEN 16 +#define CONFIG_SUPPORT_STATIC_ALLOCATION 1 +#define CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK 1 + +#define CONFIG_MAIN_TASK_STACK_SIZE 4096 +#define CONFIG_IPC_TASK_STACK_SIZE 1024 +#define CONFIG_BTC_TASK_STACK_SIZE 3072 +#define CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE 4096 +#define CONFIG_SYSTEM_EVENT_QUEUE_SIZE 32 +#define CONFIG_TIMER_TASK_STACK_SIZE 4096 +#define CONFIG_TIMER_TASK_PRIORITY 1 +#define CONFIG_TIMER_TASK_STACK_DEPTH 2048 +#define CONFIG_TIMER_QUEUE_LENGTH 10 + +#define CONFIG_NEWLIB_STDIN_LINE_ENDING_CR 1 +#define CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF 1 +#define CONFIG_PHY_ENABLED 1 +#define CONFIG_WIFI_ENABLED 1 +#define CONFIG_OPTIMIZATION_LEVEL_DEBUG 1 +#define CONFIG_MEMMAP_SMP 1 + +#define CONFIG_PARTITION_TABLE_SINGLE_APP 1 +#define CONFIG_PARTITION_TABLE_FILENAME "partitions_singleapp.csv" +#define CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET 0x10000 +#define CONFIG_PARTITION_TABLE_CUSTOM_FILENAME "partitions.csv" + +#define CONFIG_CONSOLE_UART_BAUDRATE 115200 +#define CONFIG_CONSOLE_UART_NUM 0 +#define CONFIG_CONSOLE_UART_DEFAULT 1 + +#define CONFIG_LOG_DEFAULT_LEVEL_INFO 1 +#define CONFIG_LOG_BOOTLOADER_LEVEL_WARN 1 +#define CONFIG_LOG_DEFAULT_LEVEL 3 +#define CONFIG_LOG_COLORS 1 +#define CONFIG_LOG_BOOTLOADER_LEVEL 2 + +#define CONFIG_LWIP_THREAD_LOCAL_STORAGE_INDEX 0 +#define CONFIG_LWIP_DHCP_DOES_ARP_CHECK 1 +#define CONFIG_LWIP_DHCP_MAX_NTP_SERVERS 1 +#define CONFIG_LWIP_MAX_SOCKETS 8 +#define CONFIG_LWIP_SO_REUSE 1 +#define CONFIG_IP_LOST_TIMER_INTERVAL 120 +#define CONFIG_UDP_RECVMBOX_SIZE 6 +#define CONFIG_TCP_MAXRTX 12 +#define CONFIG_TCP_SYNMAXRTX 6 +#define CONFIG_TCP_MSL 60000 +#define CONFIG_TCP_MSS 1436 +#define CONFIG_TCP_SND_BUF_DEFAULT 5744 +#define CONFIG_TCP_WND_DEFAULT 5744 +#define CONFIG_TCP_QUEUE_OOSEQ 1 +#define CONFIG_TCP_OVERSIZE_MSS 1 +#define CONFIG_TCP_RECVMBOX_SIZE 6 + +#define CONFIG_MBEDTLS_AES_C 1 +#define CONFIG_MBEDTLS_CCM_C 1 +#define CONFIG_MBEDTLS_ECDH_C 1 +#define CONFIG_MBEDTLS_ECDSA_C 1 +#define CONFIG_MBEDTLS_ECP_C 1 +#define CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_NIST_OPTIM 1 +#define CONFIG_MBEDTLS_GCM_C 1 +#define CONFIG_MBEDTLS_HARDWARE_AES 1 +#define CONFIG_MBEDTLS_HAVE_TIME 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_RSA 1 +#define CONFIG_MBEDTLS_PEM_PARSE_C 1 +#define CONFIG_MBEDTLS_PEM_WRITE_C 1 +#define CONFIG_MBEDTLS_RC4_DISABLED 1 +#define CONFIG_MBEDTLS_SSL_ALPN 1 +#define CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN 16384 +#define CONFIG_MBEDTLS_SSL_PROTO_TLS1 1 +#define CONFIG_MBEDTLS_SSL_PROTO_TLS1_1 1 +#define CONFIG_MBEDTLS_SSL_PROTO_TLS1_2 1 +#define CONFIG_MBEDTLS_SSL_RENEGOTIATION 1 +#define CONFIG_MBEDTLS_SSL_SESSION_TICKETS 1 +#define CONFIG_MBEDTLS_TLS_CLIENT 1 +#define CONFIG_MBEDTLS_TLS_ENABLED 1 +#define CONFIG_MBEDTLS_TLS_SERVER 1 +#define CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT 1 +#define CONFIG_MBEDTLS_X509_CRL_PARSE_C 1 +#define CONFIG_MBEDTLS_X509_CSR_PARSE_C 1 + +#define CONFIG_MAKE_WARN_UNDEFINED_VARIABLES 1 +#define CONFIG_TOOLPREFIX "xtensa-esp32-elf-" +#define CONFIG_PYTHON "python2" diff --git a/ports/esp32/uart.c b/ports/esp32/uart.c new file mode 100644 index 0000000000..10a4ba462e --- /dev/null +++ b/ports/esp32/uart.c @@ -0,0 +1,65 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "driver/uart.h" + +#include "py/mpstate.h" +#include "py/mphal.h" + +STATIC void uart_irq_handler(void *arg); + +void uart_init(void) { + uart_isr_handle_t handle; + uart_isr_register(UART_NUM_0, uart_irq_handler, NULL, ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM, &handle); + uart_enable_rx_intr(UART_NUM_0); +} + +// all code executed in ISR must be in IRAM, and any const data must be in DRAM +STATIC void IRAM_ATTR uart_irq_handler(void *arg) { + volatile uart_dev_t *uart = &UART0; + uart->int_clr.rxfifo_full = 1; + uart->int_clr.frm_err = 1; + uart->int_clr.rxfifo_tout = 1; + while (uart->status.rxfifo_cnt) { + uint8_t c = uart->fifo.rw_byte; + if (c == mp_interrupt_char) { + // inline version of mp_keyboard_interrupt(); + MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)); + #if MICROPY_ENABLE_SCHEDULER + if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) { + MP_STATE_VM(sched_state) = MP_SCHED_PENDING; + } + #endif + } else { + // this is an inline function so will be in IRAM + ringbuf_put(&stdin_ringbuf, c); + } + } +} diff --git a/ports/esp32/uart.h b/ports/esp32/uart.h new file mode 100644 index 0000000000..264c8b8949 --- /dev/null +++ b/ports/esp32/uart.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_ESP32_UART_H +#define MICROPY_INCLUDED_ESP32_UART_H + +void uart_init(void); + +#endif // MICROPY_INCLUDED_ESP32_UART_H From bfc9845d005b361cc1ba58939c6d3317aeb37a07 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 15 Sep 2017 13:29:36 +1000 Subject: [PATCH 132/828] esp32/modnetwork: Give better error msgs for AP timeout and not-found. --- ports/esp32/modnetwork.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index 73a4718617..af1c9301c4 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -130,8 +130,16 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) { system_event_sta_disconnected_t *disconn = &event->event_info.disconnected; ESP_LOGI("wifi", "STA_DISCONNECTED, reason:%d", disconn->reason); switch (disconn->reason) { + case WIFI_REASON_BEACON_TIMEOUT: + mp_printf(MP_PYTHON_PRINTER, "beacon timeout\n"); + // AP has dropped out; try to reconnect. + break; + case WIFI_REASON_NO_AP_FOUND: + mp_printf(MP_PYTHON_PRINTER, "no AP found\n"); + // AP may not exist, or it may have momentarily dropped out; try to reconnect. + break; case WIFI_REASON_AUTH_FAIL: - mp_printf(MP_PYTHON_PRINTER, "authentication failed"); + mp_printf(MP_PYTHON_PRINTER, "authentication failed\n"); wifi_sta_connected = false; break; default: From 6cc716c4aa86f35f14930abbb02c6d63f9329aa1 Mon Sep 17 00:00:00 2001 From: Timmenem Date: Fri, 22 Sep 2017 12:31:10 +0200 Subject: [PATCH 133/828] esp32/modsocket: Implement setsockopt(IP_ADD_MEMBERSHIP). Allows to join multicast groups. --- ports/esp32/modsocket.c | 42 +++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 6ba61e874f..cba34d76c7 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -51,6 +51,7 @@ #include "lwip/sockets.h" #include "lwip/netdb.h" #include "lwip/ip4.h" +#include "lwip/igmp.h" #include "esp_log.h" #define SOCKET_POLL_US (100000) @@ -208,18 +209,37 @@ STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { (void)n_args; // always 4 socket_obj_t *self = MP_OBJ_TO_PTR(args[0]); - int level = mp_obj_get_int(args[1]); - if (level != SOL_SOCKET) { - mp_raise_ValueError("unsupported level"); - } - - // only "int" arguments are supported at the moment int opt = mp_obj_get_int(args[2]); - int val = mp_obj_get_int(args[3]); - int ret = lwip_setsockopt_r(self->fd, SOL_SOCKET, opt, &val, sizeof(int)); - if (ret != 0) { - exception_from_errno(errno); + switch (opt) { + // level: SOL_SOCKET + case SO_REUSEADDR: { + int val = mp_obj_get_int(args[3]); + int ret = lwip_setsockopt_r(self->fd, SOL_SOCKET, opt, &val, sizeof(int)); + if (ret != 0) { + exception_from_errno(errno); + } + break; + } + + // level: IPPROTO_IP + case IP_ADD_MEMBERSHIP: { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + if (bufinfo.len != sizeof(ip4_addr_t) * 2) { + mp_raise_ValueError(NULL); + } + + // POSIX setsockopt has order: group addr, if addr, lwIP has it vice-versa + err_t err = igmp_joingroup((const ip4_addr_t*)bufinfo.buf + 1, bufinfo.buf); + if (err != ERR_OK) { + mp_raise_OSError(-err); + } + break; + } + + default: + mp_printf(&mp_plat_print, "Warning: lwip.setsockopt() option not implemented\n"); } return mp_const_none; @@ -558,8 +578,10 @@ STATIC const mp_map_elem_t mp_module_socket_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_RAW), MP_OBJ_NEW_SMALL_INT(SOCK_RAW) }, { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_TCP), MP_OBJ_NEW_SMALL_INT(IPPROTO_TCP) }, { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_UDP), MP_OBJ_NEW_SMALL_INT(IPPROTO_UDP) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_IP), MP_OBJ_NEW_SMALL_INT(IPPROTO_IP) }, { MP_OBJ_NEW_QSTR(MP_QSTR_SOL_SOCKET), MP_OBJ_NEW_SMALL_INT(SOL_SOCKET) }, { MP_OBJ_NEW_QSTR(MP_QSTR_SO_REUSEADDR), MP_OBJ_NEW_SMALL_INT(SO_REUSEADDR) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IP_ADD_MEMBERSHIP), MP_OBJ_NEW_SMALL_INT(IP_ADD_MEMBERSHIP) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_socket_globals, mp_module_socket_globals_table); From b74809c70a78cc7fd7796f46776b17f8cf6ad3a4 Mon Sep 17 00:00:00 2001 From: Nick Moore Date: Tue, 12 Sep 2017 10:12:22 +1000 Subject: [PATCH 134/828] esp32/mpconfigport.h: Add missing uhashlib. --- ports/esp32/mpconfigport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 2c32593244..3c4b77d3d4 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -176,6 +176,7 @@ extern const struct _mp_obj_module_t mp_module_onewire; { MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&mp_module_machine }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_network), (mp_obj_t)&mp_module_network }, \ { MP_OBJ_NEW_QSTR(MP_QSTR__onewire), (mp_obj_t)&mp_module_onewire }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_uhashlib), (mp_obj_t)&mp_module_uhashlib }, \ #define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ { MP_OBJ_NEW_QSTR(MP_QSTR_binascii), (mp_obj_t)&mp_module_ubinascii }, \ From 5adc133f051172ebbc5b6fb3d8913599f5df3c06 Mon Sep 17 00:00:00 2001 From: Eric Poulsen Date: Fri, 29 Sep 2017 09:00:55 -0700 Subject: [PATCH 135/828] esp32/mphalport.h: Make mp_hal_pin_ select gpio on the pad. Otherwise interfaces like software I2C and SPI don't initialise correctly. --- ports/esp32/mphalport.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/esp32/mphalport.h b/ports/esp32/mphalport.h index 8a0f1dc8b0..3215bc062c 100644 --- a/ports/esp32/mphalport.h +++ b/ports/esp32/mphalport.h @@ -59,12 +59,15 @@ mp_hal_pin_obj_t machine_pin_get_id(mp_obj_t pin_in); #define mp_obj_get_pin(o) machine_pin_get_id(o) // legacy name; only to support esp8266/modonewire #define mp_hal_pin_name(p) (p) static inline void mp_hal_pin_input(mp_hal_pin_obj_t pin) { + gpio_pad_select_gpio(pin); gpio_set_direction(pin, GPIO_MODE_INPUT); } static inline void mp_hal_pin_output(mp_hal_pin_obj_t pin) { + gpio_pad_select_gpio(pin); gpio_set_direction(pin, GPIO_MODE_INPUT_OUTPUT); } static inline void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin) { + gpio_pad_select_gpio(pin); gpio_set_direction(pin, GPIO_MODE_INPUT_OUTPUT_OD); } static inline void mp_hal_pin_od_low(mp_hal_pin_obj_t pin) { From 5f8ad6072f16414e6fc31125a38f21c366e0cb34 Mon Sep 17 00:00:00 2001 From: Nick Moore Date: Thu, 5 Oct 2017 22:06:26 +1100 Subject: [PATCH 136/828] esp32: Call initialization function on sha1 and sha256. Add in calls to mbedtls_sha1_starts() and mbedtls_sha256_starts(). --- ports/esp32/moduhashlib.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/esp32/moduhashlib.c b/ports/esp32/moduhashlib.c index 6f67aa7d9d..e8bc5e83c7 100644 --- a/ports/esp32/moduhashlib.c +++ b/ports/esp32/moduhashlib.c @@ -46,6 +46,7 @@ STATIC mp_obj_t sha256_make_new(const mp_obj_type_t *type, mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(union sha_ctxs)); o->base.type = type; mbedtls_sha256_init(&o->state.sha256); + mbedtls_sha256_starts(&o->state.sha256, 0); if (n_args == 1) { sha256_update(MP_OBJ_FROM_PTR(o), args[0]); } @@ -58,6 +59,7 @@ STATIC mp_obj_t sha1_make_new(const mp_obj_type_t *type, mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(union sha_ctxs)); o->base.type = type; mbedtls_sha1_init(&o->state.sha1); + mbedtls_sha1_starts(&o->state.sha1); if (n_args == 1) { sha1_update(MP_OBJ_FROM_PTR(o), args[0]); } From 31747fe2660c5c48dd8546ce3665e798d36698aa Mon Sep 17 00:00:00 2001 From: Eric Poulsen Date: Tue, 23 May 2017 09:24:51 -0700 Subject: [PATCH 137/828] esp32: Implement machine.WDT() class. --- ports/esp32/Makefile | 1 + ports/esp32/machine_wdt.c | 78 +++++++++++++++++++++++++++++++++++++++ ports/esp32/modmachine.c | 1 + ports/esp32/modmachine.h | 1 + ports/esp32/sdkconfig.h | 1 + 5 files changed, 82 insertions(+) create mode 100644 ports/esp32/machine_wdt.c diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 2eae802be5..a461f50ff4 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -141,6 +141,7 @@ SRC_C = \ moduhashlib.c \ espneopixel.c \ machine_hw_spi.c \ + machine_wdt.c \ mpthreadport.c \ $(SRC_MOD) diff --git a/ports/esp32/machine_wdt.c b/ports/esp32/machine_wdt.c new file mode 100644 index 0000000000..0389e86896 --- /dev/null +++ b/ports/esp32/machine_wdt.c @@ -0,0 +1,78 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * Copyright (c) 2017 Eric Poulsen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/nlr.h" +#include "py/obj.h" +#include "py/runtime.h" + +#include "esp_task_wdt.h" + +const mp_obj_type_t machine_wdt_type; + +typedef struct _machine_wdt_obj_t { + mp_obj_base_t base; +} machine_wdt_obj_t; + +STATIC machine_wdt_obj_t wdt_default = {{&machine_wdt_type}}; + +STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + + mp_int_t id = 0; + if (n_args > 0) { + id = mp_obj_get_int(args[0]); + } + + switch (id) { + case 0: + esp_task_wdt_feed(); + return &wdt_default; + default: + mp_raise_ValueError(NULL); + } +} + +STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) { + (void)self_in; + esp_task_wdt_feed(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed); + +STATIC const mp_map_elem_t machine_wdt_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_feed), (mp_obj_t)&machine_wdt_feed_obj }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_wdt_locals_dict, machine_wdt_locals_dict_table); + +const mp_obj_type_t machine_wdt_type = { + { &mp_type_type }, + .name = MP_QSTR_WDT, + .make_new = machine_wdt_make_new, + .locals_dict = (mp_obj_t)&machine_wdt_locals_dict, +}; diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index 51038f3141..32c9c5ad5f 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -114,6 +114,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) }, { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) }, + { MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&machine_wdt_type) }, { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, { MP_ROM_QSTR(MP_QSTR_TouchPad), MP_ROM_PTR(&machine_touchpad_type) }, diff --git a/ports/esp32/modmachine.h b/ports/esp32/modmachine.h index 4909235b46..58229007d7 100644 --- a/ports/esp32/modmachine.h +++ b/ports/esp32/modmachine.h @@ -4,6 +4,7 @@ #include "py/obj.h" extern const mp_obj_type_t machine_timer_type; +extern const mp_obj_type_t machine_wdt_type; extern const mp_obj_type_t machine_pin_type; extern const mp_obj_type_t machine_touchpad_type; extern const mp_obj_type_t machine_adc_type; diff --git a/ports/esp32/sdkconfig.h b/ports/esp32/sdkconfig.h index ce254c0e6d..38050fab2f 100644 --- a/ports/esp32/sdkconfig.h +++ b/ports/esp32/sdkconfig.h @@ -45,6 +45,7 @@ #define CONFIG_INT_WDT_TIMEOUT_MS 300 #define CONFIG_INT_WDT_CHECK_CPU1 0 #define CONFIG_TASK_WDT 1 +#define CONFIG_TASK_WDT_PANIC 1 #define CONFIG_TASK_WDT_TIMEOUT_S 5 #define CONFIG_TASK_WDT_CHECK_IDLE_TASK 0 #define CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1 0 From ba2d960276083c12b2ccf6f431064ab4a073a73d Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 15 Oct 2017 18:14:37 +1100 Subject: [PATCH 138/828] esp32/README: Update general description of port to add avail features. --- ports/esp32/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ports/esp32/README.md b/ports/esp32/README.md index 7591f040a6..5c0eb813d6 100644 --- a/ports/esp32/README.md +++ b/ports/esp32/README.md @@ -7,12 +7,14 @@ a task under FreeRTOS. Supported features include: - REPL (Python prompt) over UART0. -- 16k stack for the MicroPython task and 64k Python heap. +- 16k stack for the MicroPython task and 96k Python heap. - Many of MicroPython's features are enabled: unicode, arbitrary-precision integers, single-precision floats, complex numbers, frozen bytecode, as well as many of the internal modules. -- Internal filesystem using the flash (currently 256k in size). -- The machine module with basic GPIO and bit-banging I2C, SPI support. +- Internal filesystem using the flash (currently 2M in size). +- The machine module with GPIO, UART, SPI, software I2C, ADC, DAC, PWM, + TouchPad, WDT and Timer. +- The network module with WLAN (WiFi) support. Development of this ESP32 port was sponsored in part by Microbric Pty Ltd. From f0628f5499774817ccbf34e66b22c56ec8e68a90 Mon Sep 17 00:00:00 2001 From: Nick Moore Date: Thu, 19 Oct 2017 11:01:53 +1100 Subject: [PATCH 139/828] esp32/modutime.c: Add localtime and mktime functions. --- ports/esp32/modutime.c | 45 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/ports/esp32/modutime.c b/ports/esp32/modutime.c index f037faad95..002854298b 100644 --- a/ports/esp32/modutime.c +++ b/ports/esp32/modutime.c @@ -30,8 +30,51 @@ #include #include +#include "py/runtime.h" +#include "lib/timeutils/timeutils.h" #include "extmod/utime_mphal.h" +STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) { + timeutils_struct_time_t tm; + mp_int_t seconds; + if (n_args == 0 || args[0] == mp_const_none) { + struct timeval tv; + gettimeofday(&tv, NULL); + seconds = tv.tv_sec; + } else { + seconds = mp_obj_get_int(args[0]); + } + timeutils_seconds_since_2000_to_struct_time(seconds, &tm); + mp_obj_t tuple[8] = { + tuple[0] = mp_obj_new_int(tm.tm_year), + tuple[1] = mp_obj_new_int(tm.tm_mon), + tuple[2] = mp_obj_new_int(tm.tm_mday), + tuple[3] = mp_obj_new_int(tm.tm_hour), + tuple[4] = mp_obj_new_int(tm.tm_min), + tuple[5] = mp_obj_new_int(tm.tm_sec), + tuple[6] = mp_obj_new_int(tm.tm_wday), + tuple[7] = mp_obj_new_int(tm.tm_yday), + }; + return mp_obj_new_tuple(8, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime); + +STATIC mp_obj_t time_mktime(mp_obj_t tuple) { + size_t len; + mp_obj_t *elem; + mp_obj_get_array(tuple, &len, &elem); + + // localtime generates a tuple of len 8. CPython uses 9, so we accept both. + if (len < 8 || len > 9) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "mktime needs a tuple of length 8 or 9 (%d given)", len)); + } + + return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]), + mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]), + mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5]))); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime); + STATIC mp_obj_t time_time(void) { struct timeval tv; gettimeofday(&tv, NULL); @@ -42,6 +85,8 @@ MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); STATIC const mp_rom_map_elem_t time_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, + { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&time_localtime_obj) }, + { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_mktime_obj) }, { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) }, { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) }, { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, From a5808e2fca043dcacc2de8563533f71d1a12fb39 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 26 Oct 2017 17:17:08 +1100 Subject: [PATCH 140/828] esp32/machine_pwm: Always set the channel in the PWM object. --- ports/esp32/machine_pwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp32/machine_pwm.c b/ports/esp32/machine_pwm.c index 489833e7c2..4d6c59f0fa 100644 --- a/ports/esp32/machine_pwm.c +++ b/ports/esp32/machine_pwm.c @@ -131,6 +131,7 @@ STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self, } channel = avail; } + self->channel = channel; // New PWM assignment self->active = 1; @@ -148,7 +149,6 @@ STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self, "PWM not supported on pin %d", self->pin)); } chan_gpio[channel] = self->pin; - self->channel = channel; } // Maybe change PWM timer From 48613b6011fc84136125b7595e1e2cca673e7ed5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 26 Oct 2017 18:24:35 +1100 Subject: [PATCH 141/828] esp32: Update to latest ESP IDF. This update requires the xtensa-esp32-elf to be upgraded to the latest version, 1.22.0-73-ge28a011-5.2.0. --- ports/esp32/Makefile | 8 ++++++-- ports/esp32/esp32.custom_common.ld | 8 ++++++-- ports/esp32/sdkconfig.h | 6 ++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index a461f50ff4..a533fd31d0 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -29,7 +29,7 @@ ESPCOMP = $(ESPIDF)/components ESPTOOL ?= $(ESPCOMP)/esptool_py/esptool/esptool.py # verify the ESP IDF version -ESPIDF_SUPHASH := 9a26296a0e88a4c3ae27e9c848be970946fff87e +ESPIDF_SUPHASH := 2c95a77cf93781f296883d5dbafcdc18e4389656 ESPIDF_CURHASH := $(shell git -C $(ESPIDF) show -s --pretty=format:'%H') ifneq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH)) $(info ** WARNING **) @@ -214,6 +214,7 @@ ESPIDF_DRIVER_O = $(addprefix $(ESPCOMP)/driver/,\ $(BUILD)/$(ESPCOMP)/esp32/dport_access.o: CFLAGS += -Wno-array-bounds ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\ + brownout.o \ panic.o \ esp_timer.o \ esp_timer_esp32.o \ @@ -240,6 +241,7 @@ ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\ intr_alloc.o \ dport_access.o \ wifi_init.o \ + wifi_internal.o \ ) ESPIDF_HEAP_O = $(addprefix $(ESPCOMP)/heap/,\ @@ -281,6 +283,7 @@ ESPIDF_EXPAT_O = $(addprefix $(ESPCOMP)/expat/,\ ESPIDF_PTHREAD_O = $(addprefix $(ESPCOMP)/pthread/,\ pthread.o \ + pthread_local_storage.o \ ) # Assembler .S files need only basic flags, and in particular should not have @@ -447,6 +450,7 @@ ESPIDF_LWIP_O = $(addprefix $(ESPCOMP)/lwip/,\ port/freertos/sys_arch.o \ port/netif/wlanif.o \ port/netif/ethernetif.o \ + port/vfs_lwip.o \ ) ESPIDF_MBEDTLS_O = $(addprefix $(ESPCOMP)/mbedtls/,\ @@ -615,7 +619,7 @@ APP_LD_ARGS += -L$(dir $(LIBSTDCXX_FILE_NAME)) -lstdc++ APP_LD_ARGS += $(ESPCOMP)/newlib/lib/libc.a APP_LD_ARGS += $(ESPCOMP)/newlib/lib/libm.a APP_LD_ARGS += $(ESPCOMP)/esp32/libhal.a -APP_LD_ARGS += -L$(ESPCOMP)/esp32/lib -lcore -lnet80211 -lphy -lrtc -lpp -lwpa -lsmartconfig -lcoexist +APP_LD_ARGS += -L$(ESPCOMP)/esp32/lib -lcore -lnet80211 -lphy -lrtc -lpp -lwpa -lsmartconfig -lcoexist -lwps -lwpa2 APP_LD_ARGS += $(OBJ) APP_LD_ARGS += --end-group diff --git a/ports/esp32/esp32.custom_common.ld b/ports/esp32/esp32.custom_common.ld index 45242f9af2..eb1dee3c0f 100644 --- a/ports/esp32/esp32.custom_common.ld +++ b/ports/esp32/esp32.custom_common.ld @@ -89,13 +89,14 @@ SECTIONS *esp32/core_dump.o(.literal .text .literal.* .text.*) *app_trace/*(.literal .text .literal.* .text.*) *xtensa-debug-module/eri.o(.literal .text .literal.* .text.*) - *esp32/app_trace.o(.literal .text .literal.* .text.*) *libphy.a:(.literal .text .literal.* .text.*) *librtc.a:(.literal .text .literal.* .text.*) *libsoc.a:(.literal .text .literal.* .text.*) *libhal.a:(.literal .text .literal.* .text.*) *libgcc.a:lib2funcs.o(.literal .text .literal.* .text.*) *spi_flash/spi_flash_rom_patch.o(.literal .text .literal.* .text.*) + *libgcov.a:(.literal .text .literal.* .text.*) + INCLUDE esp32.spiram.rom-functions-iram.ld *py/scheduler.o*(.literal .text .literal.* .text.*) _iram_text_end = ABSOLUTE(.); } > iram0_0_seg @@ -117,9 +118,12 @@ SECTIONS *(.dram1 .dram1.*) *esp32/panic.o(.rodata .rodata.*) *libphy.a:(.rodata .rodata.*) - *app_trace/app_trace.o:(.rodata .rodata.*) + *soc/esp32/rtc_clk.o(.rodata .rodata.*) + *app_trace/app_trace.o(.rodata .rodata.*) + *libgcov.a:(.rodata .rodata.*) *heap/multi_heap.o(.rodata .rodata.*) *heap/multi_heap_poisoning.o(.rodata .rodata.*) + INCLUDE esp32.spiram.rom-functions-dram.ld _data_end = ABSOLUTE(.); . = ALIGN(4); } >dram0_0_seg diff --git a/ports/esp32/sdkconfig.h b/ports/esp32/sdkconfig.h index 38050fab2f..7fcbb7c019 100644 --- a/ports/esp32/sdkconfig.h +++ b/ports/esp32/sdkconfig.h @@ -8,7 +8,12 @@ #define CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS 1 #define CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS 4 +#define CONFIG_BROWNOUT_DET 1 +#define CONFIG_BROWNOUT_DET_LVL 0 +#define CONFIG_BROWNOUT_DET_LVL_SEL_0 1 + #define CONFIG_TCPIP_TASK_STACK_SIZE 2560 +#define CONFIG_TCPIP_RECVMBOX_SIZE 32 #define CONFIG_ESP32_APPTRACE_DEST_NONE 1 #define CONFIG_ESP32_PHY_MAX_TX_POWER 20 @@ -101,6 +106,7 @@ #define CONFIG_LWIP_DHCP_MAX_NTP_SERVERS 1 #define CONFIG_LWIP_MAX_SOCKETS 8 #define CONFIG_LWIP_SO_REUSE 1 +#define CONFIG_LWIP_ETHARP_TRUST_IP_MAC 1 #define CONFIG_IP_LOST_TIMER_INTERVAL 120 #define CONFIG_UDP_RECVMBOX_SIZE 6 #define CONFIG_TCP_MAXRTX 12 From 934abc9b9d3ddcb194f4687144b6deb3e2430cd9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 26 Oct 2017 18:25:41 +1100 Subject: [PATCH 142/828] esp32/modules: Symlink in ntptime.py from esp8266/modules. --- ports/esp32/modules/ntptime.py | 1 + 1 file changed, 1 insertion(+) create mode 120000 ports/esp32/modules/ntptime.py diff --git a/ports/esp32/modules/ntptime.py b/ports/esp32/modules/ntptime.py new file mode 120000 index 0000000000..e90900d5a9 --- /dev/null +++ b/ports/esp32/modules/ntptime.py @@ -0,0 +1 @@ +../../esp8266/modules/ntptime.py \ No newline at end of file From b0853b5a39eb46523a137ec50e777678e85d2cbf Mon Sep 17 00:00:00 2001 From: Eric Poulsen Date: Sun, 29 Oct 2017 17:10:00 -0700 Subject: [PATCH 143/828] esp32/modnetwork.c: Fix for setting DNS with network.WLAN.ifconfig(). When configuring a static set of values with ifconfig() the DNS was not being set. This patch fixes that, and additionally uses the tcpip_adapter API to ensure it is thread safe. Further discussion is here: https://github.com/micropython/micropython-esp32/issues/210/ --- ports/esp32/modnetwork.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index af1c9301c4..83f321dc22 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -328,16 +328,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_isconnected_obj, esp_isconnected); STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) { wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); tcpip_adapter_ip_info_t info; - ip_addr_t dns_addr; + tcpip_adapter_dns_info_t dns_info; tcpip_adapter_get_ip_info(self->if_id, &info); + tcpip_adapter_get_dns_info(self->if_id, TCPIP_ADAPTER_DNS_MAIN, &dns_info); if (n_args == 1) { // get - dns_addr = dns_getserver(0); mp_obj_t tuple[4] = { netutils_format_ipv4_addr((uint8_t*)&info.ip, NETUTILS_BIG), netutils_format_ipv4_addr((uint8_t*)&info.netmask, NETUTILS_BIG), netutils_format_ipv4_addr((uint8_t*)&info.gw, NETUTILS_BIG), - netutils_format_ipv4_addr((uint8_t*)&dns_addr, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&dns_info.ip, NETUTILS_BIG), }; return mp_obj_new_tuple(4, tuple); } else { @@ -356,16 +356,18 @@ STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) { netutils_parse_ipv4_addr(items[1], (void*)&info.netmask, NETUTILS_BIG); } netutils_parse_ipv4_addr(items[2], (void*)&info.gw, NETUTILS_BIG); - netutils_parse_ipv4_addr(items[3], (void*)&dns_addr, NETUTILS_BIG); + netutils_parse_ipv4_addr(items[3], (void*)&dns_info.ip, NETUTILS_BIG); // To set a static IP we have to disable DHCP first if (self->if_id == WIFI_IF_STA) { esp_err_t e = tcpip_adapter_dhcpc_stop(WIFI_IF_STA); if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) _esp_exceptions(e); ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(WIFI_IF_STA, &info)); + ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(WIFI_IF_STA, TCPIP_ADAPTER_DNS_MAIN, &dns_info)); } else if (self->if_id == WIFI_IF_AP) { esp_err_t e = tcpip_adapter_dhcps_stop(WIFI_IF_AP); if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) _esp_exceptions(e); ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(WIFI_IF_AP, &info)); + ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(WIFI_IF_AP, TCPIP_ADAPTER_DNS_MAIN, &dns_info)); ESP_EXCEPTIONS(tcpip_adapter_dhcps_start(WIFI_IF_AP)); } return mp_const_none; From 1c52d3e8c64f7d4369bf43fc0eb0cbeb76e32c03 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 30 Oct 2017 16:19:52 +1100 Subject: [PATCH 144/828] esp32/mpconfigport.h: Enable ussl finaliser. --- ports/esp32/mpconfigport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 3c4b77d3d4..1eb4c408d3 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -138,6 +138,7 @@ #define MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE (ets_get_cpu_frequency() * 1000000 / 200) // roughly #define MICROPY_PY_USSL (1) #define MICROPY_SSL_MBEDTLS (1) +#define MICROPY_PY_USSL_FINALISER (1) #define MICROPY_PY_WEBSOCKET (0) #define MICROPY_PY_FRAMEBUF (1) From 7df2ebbfeaf390cc257c56916c5af94c7785469f Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 31 Oct 2017 15:54:15 +1100 Subject: [PATCH 145/828] extmod/modussl_mbedtls: Clean up mbedtls state when error during setup. Without this patch, if the SSL handshake fails (eg the connection was lost) then the mbedtls state (memory) will never be freed. --- extmod/modussl_mbedtls.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/extmod/modussl_mbedtls.c b/extmod/modussl_mbedtls.c index 69a64d2f7a..197a0651c6 100644 --- a/extmod/modussl_mbedtls.c +++ b/extmod/modussl_mbedtls.c @@ -141,8 +141,7 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { const byte seed[] = "upy"; ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, null_entropy_func/*mbedtls_entropy_func*/, &o->entropy, seed, sizeof(seed)); if (ret != 0) { - printf("ret=%d\n", ret); - assert(0); + goto cleanup; } ret = mbedtls_ssl_config_defaults(&o->conf, @@ -150,7 +149,7 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); if (ret != 0) { - assert(0); + goto cleanup; } mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_NONE); @@ -161,14 +160,14 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { ret = mbedtls_ssl_setup(&o->ssl, &o->conf); if (ret != 0) { - assert(0); + goto cleanup; } if (args->server_hostname.u_obj != mp_const_none) { const char *sni = mp_obj_str_get_str(args->server_hostname.u_obj); ret = mbedtls_ssl_set_hostname(&o->ssl, sni); if (ret != 0) { - assert(0); + goto cleanup; } } @@ -194,13 +193,27 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { - //assert(0); printf("mbedtls_ssl_handshake error: -%x\n", -ret); - mp_raise_OSError(MP_EIO); + goto cleanup; } } return o; + +cleanup: + mbedtls_pk_free(&o->pkey); + mbedtls_x509_crt_free(&o->cert); + mbedtls_x509_crt_free(&o->cacert); + mbedtls_ssl_free(&o->ssl); + mbedtls_ssl_config_free(&o->conf); + mbedtls_ctr_drbg_free(&o->ctr_drbg); + mbedtls_entropy_free(&o->entropy); + + if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) { + mp_raise_OSError(MP_ENOMEM); + } else { + mp_raise_OSError(MP_EIO); + } } STATIC mp_obj_t mod_ssl_getpeercert(mp_obj_t o_in, mp_obj_t binary_form) { From 29dd6a7678dfbc63ef20a273014ed762af6c738f Mon Sep 17 00:00:00 2001 From: Eric Poulsen Date: Wed, 27 Sep 2017 14:59:49 -0700 Subject: [PATCH 146/828] esp32: Implement wired Ethernet via network.LAN(). Updates to Makefile, modnetwork.c, and addition of network_lan.c to implement `network.LAN()` object for wired PHY objects. --- ports/esp32/Makefile | 4 + ports/esp32/modnetwork.c | 44 ++++++--- ports/esp32/modnetwork.h | 34 +++++++ ports/esp32/network_lan.c | 203 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 270 insertions(+), 15 deletions(-) create mode 100644 ports/esp32/modnetwork.h create mode 100644 ports/esp32/network_lan.c diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index a533fd31d0..48d4b9d5cd 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -136,6 +136,7 @@ SRC_C = \ machine_uart.c \ modmachine.c \ modnetwork.c \ + network_lan.c \ modsocket.c \ modesp.c \ moduhashlib.c \ @@ -267,6 +268,9 @@ ESPIDF_CXX_O = $(addprefix $(ESPCOMP)/cxx/,\ ESPIDF_ETHERNET_O = $(addprefix $(ESPCOMP)/ethernet/,\ emac_dev.o \ emac_main.o \ + eth_phy/phy_tlk110.o \ + eth_phy/phy_lan8720.o \ + eth_phy/phy_common.o \ ) $(BUILD)/$(ESPCOMP)/expat/%.o: CFLAGS += -Wno-unused-function diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index 83f321dc22..3c348fc15b 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -7,6 +7,7 @@ * The MIT License (MIT) * * Copyright (c) 2016, 2017 Nick Moore @mnemote + * Copyright (c) 2017 "Eric Poulsen" * * Based on esp8266/modnetwork.c which is Copyright (c) 2015 Paul Sokolovsky * And the ESP IDF example code which is Public Domain / CC0 @@ -48,6 +49,8 @@ #include "lwip/dns.h" #include "tcpip_adapter.h" +#include "modnetwork.h" + #define MODNETWORK_INCLUDE_CONSTANTS (1) NORETURN void _esp_exceptions(esp_err_t e) { @@ -122,7 +125,7 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) { ESP_LOGI("wifi", "STA_START"); break; case SYSTEM_EVENT_STA_GOT_IP: - ESP_LOGI("wifi", "GOT_IP"); + ESP_LOGI("network", "GOT_IP"); break; case SYSTEM_EVENT_STA_DISCONNECTED: { // This is a workaround as ESP32 WiFi libs don't currently @@ -161,7 +164,7 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) { break; } default: - ESP_LOGI("wifi", "event %d", event->event_id); + ESP_LOGI("network", "event %d", event->event_id); break; } return ESP_OK; @@ -182,6 +185,19 @@ STATIC void require_if(mp_obj_t wlan_if, int if_no) { } STATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args) { + static int initialized = 0; + if (!initialized) { + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_LOGD("modnetwork", "Initializing WiFi"); + ESP_EXCEPTIONS( esp_wifi_init(&cfg) ); + ESP_EXCEPTIONS( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); + ESP_LOGD("modnetwork", "Initialized"); + ESP_EXCEPTIONS( esp_wifi_set_mode(0) ); + ESP_EXCEPTIONS( esp_wifi_start() ); + ESP_LOGD("modnetwork", "Started"); + initialized = 1; + } + int idx = (n_args > 0) ? mp_obj_get_int(args[0]) : WIFI_IF_STA; if (idx == WIFI_IF_STA) { return MP_OBJ_FROM_PTR(&wlan_sta_obj); @@ -201,14 +217,6 @@ STATIC mp_obj_t esp_initialize() { ESP_LOGD("modnetwork", "Initializing Event Loop"); ESP_EXCEPTIONS( esp_event_loop_init(event_handler, NULL) ); ESP_LOGD("modnetwork", "esp_event_loop_init done"); - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_LOGD("modnetwork", "Initializing WiFi"); - ESP_EXCEPTIONS( esp_wifi_init(&cfg) ); - ESP_EXCEPTIONS( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); - ESP_LOGD("modnetwork", "Initialized"); - ESP_EXCEPTIONS( esp_wifi_set_mode(0) ); - ESP_EXCEPTIONS( esp_wifi_start() ); - ESP_LOGD("modnetwork", "Started"); initialized = 1; } return mp_const_none; @@ -358,11 +366,11 @@ STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) { netutils_parse_ipv4_addr(items[2], (void*)&info.gw, NETUTILS_BIG); netutils_parse_ipv4_addr(items[3], (void*)&dns_info.ip, NETUTILS_BIG); // To set a static IP we have to disable DHCP first - if (self->if_id == WIFI_IF_STA) { - esp_err_t e = tcpip_adapter_dhcpc_stop(WIFI_IF_STA); + if (self->if_id == WIFI_IF_STA || self->if_id == ESP_IF_ETH) { + esp_err_t e = tcpip_adapter_dhcpc_stop(self->if_id); if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) _esp_exceptions(e); - ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(WIFI_IF_STA, &info)); - ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(WIFI_IF_STA, TCPIP_ADAPTER_DNS_MAIN, &dns_info)); + ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(self->if_id, &info)); + ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(self->if_id, TCPIP_ADAPTER_DNS_MAIN, &dns_info)); } else if (self->if_id == WIFI_IF_AP) { esp_err_t e = tcpip_adapter_dhcps_stop(WIFI_IF_AP); if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) _esp_exceptions(e); @@ -374,7 +382,7 @@ STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) { } } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj, 1, 2, esp_ifconfig); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj, 1, 2, esp_ifconfig); STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { if (n_args != 1 && kwargs->used != 0) { @@ -533,6 +541,7 @@ STATIC const mp_map_elem_t mp_module_network_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_network) }, { MP_OBJ_NEW_QSTR(MP_QSTR___init__), (mp_obj_t)&esp_initialize_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_WLAN), (mp_obj_t)&get_wlan_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_LAN), (mp_obj_t)&get_lan_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_phy_mode), (mp_obj_t)&esp_phy_mode_obj }, #if MODNETWORK_INCLUDE_CONSTANTS @@ -560,6 +569,11 @@ STATIC const mp_map_elem_t mp_module_network_globals_table[] = { MP_OBJ_NEW_SMALL_INT(WIFI_AUTH_WPA_WPA2_PSK) }, { MP_OBJ_NEW_QSTR(MP_QSTR_AUTH_MAX), MP_OBJ_NEW_SMALL_INT(WIFI_AUTH_MAX) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_PHY_LAN8720), + MP_OBJ_NEW_SMALL_INT(PHY_LAN8720) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_PHY_TLK110), + MP_OBJ_NEW_SMALL_INT(PHY_TLK110) }, #endif }; diff --git a/ports/esp32/modnetwork.h b/ports/esp32/modnetwork.h new file mode 100644 index 0000000000..d9f56591e2 --- /dev/null +++ b/ports/esp32/modnetwork.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_ESP32_MODNETWORK_H +#define MICROPY_INCLUDED_ESP32_MODNETWORK_H + +enum { PHY_LAN8720, PHY_TLK110 }; + +MP_DECLARE_CONST_FUN_OBJ_KW(get_lan_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj); + +#endif diff --git a/ports/esp32/network_lan.c b/ports/esp32/network_lan.c new file mode 100644 index 0000000000..fba4de73ab --- /dev/null +++ b/ports/esp32/network_lan.c @@ -0,0 +1,203 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" + * + * Based on the ESP IDF example code which is Public Domain / CC0 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mphal.h" + +#include "eth_phy/phy.h" +#include "eth_phy/phy_tlk110.h" +#include "eth_phy/phy_lan8720.h" +#include "tcpip_adapter.h" + +#include "modnetwork.h" + +typedef struct _lan_if_obj_t { + mp_obj_base_t base; + int if_id; // MUST BE FIRST to match wlan_if_obj_t + bool initialized; + bool active; + uint8_t mdc_pin; + uint8_t mdio_pin; + int8_t phy_power_pin; + uint8_t phy_addr; + uint8_t phy_type; + eth_phy_check_link_func link_func; + eth_phy_power_enable_func power_func; +} lan_if_obj_t; + +const mp_obj_type_t lan_if_type; +STATIC lan_if_obj_t lan_obj = {{&lan_if_type}, ESP_IF_ETH, false, false}; + +STATIC void phy_power_enable(bool enable) { + lan_if_obj_t* self = &lan_obj; + + if (self->phy_power_pin != -1) { + + if (!enable) { + // Do the PHY-specific power_enable(false) function before powering down + self->power_func(false); + } + + gpio_pad_select_gpio(self->phy_power_pin); + gpio_set_direction(self->phy_power_pin, GPIO_MODE_OUTPUT); + if (enable) { + gpio_set_level(self->phy_power_pin, 1); + } else { + gpio_set_level(self->phy_power_pin, 0); + } + + // Allow the power up/down to take effect, min 300us + vTaskDelay(1); + + if (enable) { + // Run the PHY-specific power on operations now the PHY has power + self->power_func(true); + } + } +} + +STATIC void init_lan_rmii() { + lan_if_obj_t* self = &lan_obj; + phy_rmii_configure_data_interface_pins(); + phy_rmii_smi_configure_pins(self->mdc_pin, self->mdio_pin); +} + +STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + lan_if_obj_t* self = &lan_obj; + + if (self->initialized) { + return MP_OBJ_FROM_PTR(&lan_obj); + } + + enum { ARG_id, ARG_mdc, ARG_mdio, ARG_power, ARG_phy_addr, ARG_phy_type }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_mdc, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_mdio, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_power, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (args[ARG_id].u_obj != mp_const_none) { + if (mp_obj_get_int(args[ARG_id].u_obj) != 0) { + mp_raise_ValueError("invalid LAN interface identifier"); + } + } + + self->mdc_pin = machine_pin_get_id(args[ARG_mdc].u_obj); + self->mdio_pin = machine_pin_get_id(args[ARG_mdio].u_obj); + self->phy_power_pin = args[ARG_power].u_obj == mp_const_none ? -1 : machine_pin_get_id(args[ARG_power].u_obj); + + if (args[ARG_phy_addr].u_int < 0x00 || args[ARG_phy_addr].u_int > 0x1f) { + mp_raise_ValueError("invalid phy address"); + } + + if (args[ARG_phy_type].u_int != PHY_LAN8720 && args[ARG_phy_type].u_int != PHY_TLK110) { + mp_raise_ValueError("invalid phy type"); + } + + eth_config_t config; + + switch (args[ARG_phy_type].u_int) { + case PHY_TLK110: + config = phy_tlk110_default_ethernet_config; + break; + case PHY_LAN8720: + config = phy_lan8720_default_ethernet_config; + break; + } + + self->link_func = config.phy_check_link; + + // Replace default power func with our own + self->power_func = config.phy_power_enable; + config.phy_power_enable = phy_power_enable; + + config.phy_addr = args[ARG_phy_addr].u_int; + config.gpio_config = init_lan_rmii; + config.tcpip_input = tcpip_adapter_eth_input; + + if (esp_eth_init(&config) == ESP_OK) { + self->active = false; + self->initialized = true; + } else { + mp_raise_msg(&mp_type_OSError, "esp_eth_init() failed"); + } + return MP_OBJ_FROM_PTR(&lan_obj); +} +MP_DEFINE_CONST_FUN_OBJ_KW(get_lan_obj, 0, get_lan); + +STATIC mp_obj_t lan_active(size_t n_args, const mp_obj_t *args) { + lan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + if (n_args > 1) { + if (mp_obj_is_true(args[1])) { + self->active = (esp_eth_enable() == ESP_OK); + if (!self->active) { + mp_raise_msg(&mp_type_OSError, "ethernet enable failed"); + } + } else { + self->active = !(esp_eth_disable() == ESP_OK); + if (self->active) { + mp_raise_msg(&mp_type_OSError, "ethernet disable failed"); + } + } + } + return mp_obj_new_bool(self->active); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lan_active_obj, 1, 2, lan_active); + +STATIC mp_obj_t lan_status(mp_obj_t self_in) { + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(lan_status_obj, lan_status); + +STATIC mp_obj_t lan_isconnected(mp_obj_t self_in) { + lan_if_obj_t *self = MP_OBJ_TO_PTR(self_in); + return self->active ? mp_obj_new_bool(self->link_func()) : mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(lan_isconnected_obj, lan_isconnected); + +STATIC const mp_rom_map_elem_t lan_if_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&lan_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&lan_isconnected_obj) }, + { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&lan_status_obj) }, + { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(lan_if_locals_dict, lan_if_locals_dict_table); + +const mp_obj_type_t lan_if_type = { + { &mp_type_type }, + .name = MP_QSTR_LAN, + .locals_dict = (mp_obj_dict_t*)&lan_if_locals_dict, +}; From 9acd5906754dd794e964a915bbb88fce25cb3bc5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 28 Nov 2017 12:13:47 +1100 Subject: [PATCH 147/828] esp32/mpconfigport.h: Enable websocket module. --- ports/esp32/mpconfigport.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 1eb4c408d3..69d17fd818 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -139,7 +139,7 @@ #define MICROPY_PY_USSL (1) #define MICROPY_SSL_MBEDTLS (1) #define MICROPY_PY_USSL_FINALISER (1) -#define MICROPY_PY_WEBSOCKET (0) +#define MICROPY_PY_WEBSOCKET (1) #define MICROPY_PY_FRAMEBUF (1) // fatfs configuration From 78302f7bb2b32ce8ad91d9d3a4ef55f5c7f8840e Mon Sep 17 00:00:00 2001 From: Alex King Date: Wed, 14 Jun 2017 21:03:42 -0500 Subject: [PATCH 148/828] esp32/modesp: Add osdebug() function to disable or change IDF logging. Code lineage: osdebug() is based loosely on the version in esp8266, but there didn't seem to be an obvious way of choosing a particular UART. The basic behavior is the same, though: provide None, and logging is disabled; provide an integer and logging is restored to the default level. To build on that, and because the IDF provides more functionality, a second parameter has now been implemented which allows the active log level to be set: esp.osdebug(uart[, level]) The module has a corresponding set of LOG_ values to set this accordingly. --- ports/esp32/modesp.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ports/esp32/modesp.c b/ports/esp32/modesp.c index caa0551646..e614f77a6a 100644 --- a/ports/esp32/modesp.c +++ b/ports/esp32/modesp.c @@ -30,6 +30,7 @@ #include #include "rom/gpio.h" +#include "esp_log.h" #include "esp_spi_flash.h" #include "py/runtime.h" @@ -38,6 +39,23 @@ #include "drivers/dht/dht.h" #include "modesp.h" +STATIC mp_obj_t esp_osdebug(size_t n_args, const mp_obj_t *args) { + esp_log_level_t level = LOG_LOCAL_LEVEL; + if (n_args == 2) { + level = mp_obj_get_int(args[1]); + } + if (args[0] == mp_const_none) { + // Disable logging + esp_log_level_set("*", ESP_LOG_ERROR); + } else { + // Enable logging at the given level + // TODO args[0] should set the UART to which debug is sent + esp_log_level_set("*", level); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_osdebug_obj, 1, 2, esp_osdebug); + STATIC mp_obj_t esp_flash_read(mp_obj_t offset_in, mp_obj_t buf_in) { mp_int_t offset = mp_obj_get_int(offset_in); mp_buffer_info_t bufinfo; @@ -107,6 +125,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_neopixel_write_obj, esp_neopixel_write_); STATIC const mp_rom_map_elem_t esp_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp) }, + { MP_ROM_QSTR(MP_QSTR_osdebug), MP_ROM_PTR(&esp_osdebug_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_read), MP_ROM_PTR(&esp_flash_read_obj) }, { MP_ROM_QSTR(MP_QSTR_flash_write), MP_ROM_PTR(&esp_flash_write_obj) }, { MP_ROM_QSTR(MP_QSTR_flash_erase), MP_ROM_PTR(&esp_flash_erase_obj) }, @@ -118,6 +138,14 @@ STATIC const mp_rom_map_elem_t esp_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_neopixel_write), MP_ROM_PTR(&esp_neopixel_write_obj) }, { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) }, + + // Constants for second arg of osdebug() + { MP_ROM_QSTR(MP_QSTR_LOG_NONE), MP_ROM_INT((mp_uint_t)ESP_LOG_NONE)}, + { MP_ROM_QSTR(MP_QSTR_LOG_ERROR), MP_ROM_INT((mp_uint_t)ESP_LOG_ERROR)}, + { MP_ROM_QSTR(MP_QSTR_LOG_WARNING), MP_ROM_INT((mp_uint_t)ESP_LOG_WARN)}, + { MP_ROM_QSTR(MP_QSTR_LOG_INFO), MP_ROM_INT((mp_uint_t)ESP_LOG_INFO)}, + { MP_ROM_QSTR(MP_QSTR_LOG_DEBUG), MP_ROM_INT((mp_uint_t)ESP_LOG_DEBUG)}, + { MP_ROM_QSTR(MP_QSTR_LOG_VERBOSE), MP_ROM_INT((mp_uint_t)ESP_LOG_VERBOSE)}, }; STATIC MP_DEFINE_CONST_DICT(esp_module_globals, esp_module_globals_table); From 0593d6f5627a75d6d3cc894c4cf421158dc6cedf Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 13 Dec 2017 14:56:28 +1100 Subject: [PATCH 149/828] esp32/Makefile: Support using IDF_PATH as the env var to the IDF source. --- ports/esp32/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 48d4b9d5cd..3f0e47c178 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -23,8 +23,12 @@ CROSS_COMPILE ?= xtensa-esp32-elf- # paths to ESP IDF and its components ifeq ($(ESPIDF),) +ifneq ($(IDF_PATH),) +ESPIDF = $(IDF_PATH) +else $(error Please configure the ESPIDF variable) endif +endif ESPCOMP = $(ESPIDF)/components ESPTOOL ?= $(ESPCOMP)/esptool_py/esptool/esptool.py From 19c7098e183a8148c541fe34c3fc1252dbbb90db Mon Sep 17 00:00:00 2001 From: Eric Poulsen Date: Sat, 9 Dec 2017 23:45:50 -0800 Subject: [PATCH 150/828] esp32: Add custom partitions.csv file with uPy specific size. --- ports/esp32/Makefile | 2 +- ports/esp32/partitions.csv | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 ports/esp32/partitions.csv diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 3f0e47c178..2fa8c1c506 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -721,7 +721,7 @@ $(BUILD)/bootloader.elf: $(BOOTLOADER_OBJ) # Declarations to build the partitions PYTHON2 ?= python2 -PART_SRC = $(ESPCOMP)/partition_table/partitions_singleapp.csv +PART_SRC = partitions.csv $(BUILD)/partitions.bin: $(PART_SRC) $(ECHO) "Create $@" diff --git a/ports/esp32/partitions.csv b/ports/esp32/partitions.csv new file mode 100644 index 0000000000..98adcd20a7 --- /dev/null +++ b/ports/esp32/partitions.csv @@ -0,0 +1,5 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +nvs, data, nvs, 0x9000, 0x6000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 0x180000, From 1e2b78111b196207fa632c3091c75b91d0ccd75e Mon Sep 17 00:00:00 2001 From: Ryan Finnie Date: Sat, 9 Dec 2017 22:52:27 -0800 Subject: [PATCH 151/828] docs/esp8266/tutorial: Fix typo, change -> changed. --- docs/esp8266/tutorial/powerctrl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/esp8266/tutorial/powerctrl.rst b/docs/esp8266/tutorial/powerctrl.rst index 3502624ab5..289b4c42fd 100644 --- a/docs/esp8266/tutorial/powerctrl.rst +++ b/docs/esp8266/tutorial/powerctrl.rst @@ -14,7 +14,7 @@ current frequency use:: >>> machine.freq() 80000000 -By default the CPU runs at 80MHz. It can be change to 160MHz if you need more +By default the CPU runs at 80MHz. It can be changed to 160MHz if you need more processing power, at the expense of current consumption:: >>> machine.freq(160000000) From 140bbced6f270d9baf3df3b725932ecbbd5a4577 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 11 Dec 2017 19:45:57 +0200 Subject: [PATCH 152/828] lib/upytesthelper: MicroPython test helper layer on top of tinytest. Tinytest is classical assert-style framework, but MicroPython tests work in different way - they produce content, and that content should be matched against expected one to see if test passes. upytesthelper exactly adds helper functions to make that possible. --- lib/upytesthelper/upytesthelper.c | 126 ++++++++++++++++++++++++++++++ lib/upytesthelper/upytesthelper.h | 37 +++++++++ 2 files changed, 163 insertions(+) create mode 100644 lib/upytesthelper/upytesthelper.c create mode 100644 lib/upytesthelper/upytesthelper.h diff --git a/lib/upytesthelper/upytesthelper.c b/lib/upytesthelper/upytesthelper.c new file mode 100644 index 0000000000..d28c5b9cc0 --- /dev/null +++ b/lib/upytesthelper/upytesthelper.c @@ -0,0 +1,126 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include + +#include "py/mphal.h" +#include "py/gc.h" +#include "py/runtime.h" +#include "py/compile.h" +#include "upytesthelper.h" + +static const char *test_exp_output; +static int test_exp_output_len, test_rem_output_len; +static int test_failed; +static void *heap_start, *heap_end; + +void upytest_set_heap(void *start, void *end) { + heap_start = start; + heap_end = end; +} + +void upytest_set_expected_output(const char *output, unsigned len) { + test_exp_output = output; + test_exp_output_len = test_rem_output_len = len; + test_failed = false; +} + +bool upytest_is_failed(void) { + if (test_failed) { + return true; + } + #if 0 + if (test_rem_output_len != 0) { + printf("remaining len: %d\n", test_rem_output_len); + } + #endif + return test_rem_output_len != 0; +} + +// MP_PLAT_PRINT_STRN() should be redirected to this function. +// It will pass-thru any content to mp_hal_stdout_tx_strn_cooked() +// (the dfault value of MP_PLAT_PRINT_STRN), but will also match +// it to the expected output as set by upytest_set_expected_output(). +// If mismatch happens, upytest_is_failed() returns true. +void upytest_output(const char *str, mp_uint_t len) { + if (!test_failed) { + if (len > test_rem_output_len) { + test_failed = true; + } else { + test_failed = memcmp(test_exp_output, str, len); + #if 0 + if (test_failed) { + printf("failed after char %u, within %d chars, res: %d\n", + test_exp_output_len - test_rem_output_len, (int)len, test_failed); + for (int i = 0; i < len; i++) { + if (str[i] != test_exp_output[i]) { + printf("%d %02x %02x\n", i, str[i], test_exp_output[i]); + } + } + } + #endif + test_exp_output += len; + test_rem_output_len -= len; + } + } + mp_hal_stdout_tx_strn_cooked(str, len); +} + +void upytest_execute_test(const char *src) { + // To provide clean room for each test, interpreter and heap are + // reinitialized before running each. + gc_init(heap_start, heap_end); + mp_init(); + mp_obj_list_init(mp_sys_path, 0); + mp_obj_list_init(mp_sys_argv, 0); + + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); + qstr source_name = lex->source_name; + mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, false); + mp_call_function_0(module_fun); + nlr_pop(); + } else { + mp_obj_t exc = (mp_obj_t)nlr.ret_val; + if (mp_obj_is_subclass_fast(mp_obj_get_type(exc), &mp_type_SystemExit)) { + // Assume that sys.exit() is called to skip the test. + // TODO: That can be always true, we should set up convention to + // use specific exit code as skip indicator. + tinytest_set_test_skipped_(); + goto end; + } + mp_obj_print_exception(&mp_plat_print, exc); + tt_abort_msg("Uncaught exception\n"); + } + + if (upytest_is_failed()) { + tinytest_set_test_failed_(); + } + +end: + mp_deinit(); +} diff --git a/lib/upytesthelper/upytesthelper.h b/lib/upytesthelper/upytesthelper.h new file mode 100644 index 0000000000..3a292befd7 --- /dev/null +++ b/lib/upytesthelper/upytesthelper.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include "py/mpconfig.h" +#include "lib/tinytest/tinytest.h" +#include "lib/tinytest/tinytest_macros.h" + +void upytest_set_heap(void *start, void *end); +void upytest_set_expected_output(const char *output, unsigned len); +void upytest_execute_test(const char *src); +void upytest_output(const char *str, mp_uint_t len); +bool upytest_is_failed(void); From 48e931e1d33d008c2622d3fbc5ab7e4a49296bf2 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 11 Dec 2017 19:52:06 +0200 Subject: [PATCH 153/828] tools/tinytest-codegen.py: Generate code for upytesthelper. The way tinytest was used in qemu-arm test target is that it didn't test much. MicroPython tests are based on matching the test output against reference output, but qemu-arm's implementation didn't do that, it effectively tested just that there was no exception during test execution. "upytesthelper" wrapper was introduce to fix it, and so test generator is now switched to generate test code for it. Also, fix PEP8 and other codestyle issues. --- tools/tinytest-codegen.py | 48 ++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/tools/tinytest-codegen.py b/tools/tinytest-codegen.py index dadfea1ccc..062a00935b 100755 --- a/tools/tinytest-codegen.py +++ b/tools/tinytest-codegen.py @@ -1,32 +1,38 @@ -#! /usr/bin/env python3 +#!/usr/bin/env python3 import os, sys from glob import glob from re import sub def escape(s): - lookup = { - '\0': '\\0', - '\t': '\\t', - '\n': '\\n\"\n\"', - '\r': '\\r', - '\\': '\\\\', - '\"': '\\\"', - } - return "\"\"\n\"{}\"".format(''.join([lookup[x] if x in lookup else x for x in s])) + s = s.decode() + lookup = { + '\0': '\\0', + '\t': '\\t', + '\n': '\\n\"\n\"', + '\r': '\\r', + '\\': '\\\\', + '\"': '\\\"', + } + return "\"\"\n\"{}\"".format(''.join([lookup[x] if x in lookup else x for x in s])) def chew_filename(t): - return { 'func': "test_{}_fn".format(sub(r'/|\.|-', '_', t)), 'desc': t.split('/')[1] } + return { 'func': "test_{}_fn".format(sub(r'/|\.|-', '_', t)), 'desc': t.split('/')[1] } -def script_to_map(t): - r = { 'name': chew_filename(t)['func'] } - with open(t) as f: r['script'] = escape(''.join(f.readlines())) - return r +def script_to_map(test_file): + r = {"name": chew_filename(test_file)["func"]} + with open(test_file, "rb") as f: + r["script"] = escape(f.read()) + with open(test_file + ".exp", "rb") as f: + r["output"] = escape(f.read()) + return r test_function = ( "void {name}(void* data) {{\n" - " const char * pystr = {script};\n" - " do_str(pystr);\n" + " static const char pystr[] = {script};\n" + " static const char exp[] = {output};\n" + " upytest_set_expected_output(exp, sizeof(exp) - 1);\n" + " upytest_execute_test(pystr);\n" "}}" ) @@ -57,10 +63,10 @@ exclude_tests = ( output = [] for group in test_dirs: - tests = [test for test in glob('{}/*.py'.format(group)) if test not in exclude_tests] - output.extend([test_function.format(**script_to_map(test)) for test in tests]) - testcase_members = [testcase_member.format(**chew_filename(test)) for test in tests] - output.append(testcase_struct.format(name=group, body='\n'.join(testcase_members))) + tests = [test for test in glob('{}/*.py'.format(group)) if test not in exclude_tests] + output.extend([test_function.format(**script_to_map(test)) for test in tests]) + testcase_members = [testcase_member.format(**chew_filename(test)) for test in tests] + output.append(testcase_struct.format(name=group, body='\n'.join(testcase_members))) testgroup_members = [testgroup_member.format(name=group) for group in test_dirs] From 4db6a7adbe25ba2a096cd70ec4072c168fdb4bd4 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 11 Dec 2017 19:59:11 +0200 Subject: [PATCH 154/828] tools/tinytest-codegen: Wrap lines of exclude_tests. So it was manageable and extensible. --- tools/tinytest-codegen.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tools/tinytest-codegen.py b/tools/tinytest-codegen.py index 062a00935b..6744446ea9 100755 --- a/tools/tinytest-codegen.py +++ b/tools/tinytest-codegen.py @@ -54,10 +54,16 @@ testgroup_member = ( # currently these tests are selected because they pass on qemu-arm test_dirs = ('basics', 'micropython', 'float', 'extmod', 'inlineasm') # 'import', 'io', 'misc') exclude_tests = ( - 'float/float2int_doubleprec_intbig.py', # requires double precision floating point to work - 'inlineasm/asmfpaddsub.py', 'inlineasm/asmfpcmp.py', 'inlineasm/asmfpldrstr.py', 'inlineasm/asmfpmuldiv.py', 'inlineasm/asmfpsqrt.py', - 'extmod/ticks_diff.py', 'extmod/time_ms_us.py', 'extmod/uheapq_timeq.py', - 'extmod/vfs_fat_ramdisk.py', 'extmod/vfs_fat_fileio.py', 'extmod/vfs_fat_fsusermount.py', 'extmod/vfs_fat_oldproto.py', + 'extmod/ticks_diff.py', + 'extmod/time_ms_us.py', + 'extmod/uheapq_timeq.py', + 'extmod/vfs_fat_ramdisk.py', 'extmod/vfs_fat_fileio.py', + 'extmod/vfs_fat_fsusermount.py', 'extmod/vfs_fat_oldproto.py', + # requires double precision floating point to work + 'float/float2int_doubleprec_intbig.py', + # inline asm tests + 'inlineasm/asmfpaddsub.py', 'inlineasm/asmfpcmp.py', 'inlineasm/asmfpldrstr.py', + 'inlineasm/asmfpmuldiv.py','inlineasm/asmfpsqrt.py', ) output = [] From e6f0d547ab16096d7a2c24824c6e398c082c0d50 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 11 Dec 2017 20:00:25 +0200 Subject: [PATCH 155/828] tools/tinytest-codegen: More excludes after enabling expected output match. --- tools/tinytest-codegen.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tools/tinytest-codegen.py b/tools/tinytest-codegen.py index 6744446ea9..d7761cd5ad 100755 --- a/tools/tinytest-codegen.py +++ b/tools/tinytest-codegen.py @@ -54,16 +54,31 @@ testgroup_member = ( # currently these tests are selected because they pass on qemu-arm test_dirs = ('basics', 'micropython', 'float', 'extmod', 'inlineasm') # 'import', 'io', 'misc') exclude_tests = ( + # pattern matching in .exp + 'basics/bytes_compare3.py', 'extmod/ticks_diff.py', 'extmod/time_ms_us.py', 'extmod/uheapq_timeq.py', + # unicode char issue + 'extmod/ujson_loads.py', + # doesn't output to python stdout + 'extmod/ure_debug.py', + 'extmod/vfs_basic.py', 'extmod/vfs_fat_ramdisk.py', 'extmod/vfs_fat_fileio.py', 'extmod/vfs_fat_fsusermount.py', 'extmod/vfs_fat_oldproto.py', + # rounding issues + 'float/float_divmod.py', # requires double precision floating point to work 'float/float2int_doubleprec_intbig.py', - # inline asm tests + 'float/float_parse_doubleprec.py', + # inline asm FP tests (require Cortex-M4) 'inlineasm/asmfpaddsub.py', 'inlineasm/asmfpcmp.py', 'inlineasm/asmfpldrstr.py', 'inlineasm/asmfpmuldiv.py','inlineasm/asmfpsqrt.py', + # different filename in output + 'micropython/emg_exc.py', + 'micropython/heapalloc_traceback.py', + # pattern matching in .exp + 'micropython/meminfo.py', ) output = [] From ea6bddbf8125e09d5d779d7203d402dbc093379d Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 11 Dec 2017 20:04:27 +0200 Subject: [PATCH 156/828] ports/qemu-arm: Rework "test" target using upytesthelper. The way tinytest was used in qemu-arm test target is that it didn't test much. MicroPython tests are based on matching the test output against reference output, but qemu-arm's implementation didn't do that, it effectively tested just that there was no exception during test execution. "upytesthelper" wrapper was introduce to fix it, so switch test implementation to use it. This requires passing different CFLAGS when building the firmware, so split out test-related parts to Makefile.test. --- ports/qemu-arm/Makefile | 20 +------------------- ports/qemu-arm/Makefile.test | 24 ++++++++++++++++++++++++ ports/qemu-arm/README.md | 4 ++++ ports/qemu-arm/mpconfigport.h | 7 +++++++ ports/qemu-arm/test_main.c | 30 +----------------------------- 5 files changed, 37 insertions(+), 48 deletions(-) create mode 100644 ports/qemu-arm/Makefile.test diff --git a/ports/qemu-arm/Makefile b/ports/qemu-arm/Makefile index c0d257a3eb..95f349beba 100644 --- a/ports/qemu-arm/Makefile +++ b/ports/qemu-arm/Makefile @@ -46,7 +46,7 @@ SRC_RUN_C = \ SRC_TEST_C = \ test_main.c \ -LIB_SRC_C = $(addprefix lib/,\ +LIB_SRC_C += $(addprefix lib/,\ libm/math.c \ libm/fmodf.c \ libm/nearbyintf.c \ @@ -91,27 +91,9 @@ all: run run: $(BUILD)/firmware.elf qemu-system-arm -machine integratorcp -cpu cortex-m3 -nographic -monitor null -serial null -semihosting -kernel $(BUILD)/firmware.elf -test: $(BUILD)/firmware-test.elf - qemu-system-arm -machine integratorcp -cpu cortex-m3 -nographic -monitor null -serial null -semihosting -kernel $(BUILD)/firmware-test.elf > $(BUILD)/console.out - $(Q)tail -n2 $(BUILD)/console.out - $(Q)tail -n1 $(BUILD)/console.out | grep -q "status: 0" - -.PHONY: $(BUILD)/genhdr/tests.h - -$(BUILD)/test_main.o: $(BUILD)/genhdr/tests.h -$(BUILD)/genhdr/tests.h: - $(Q)echo "Generating $@";(cd $(TOP)/tests; ../tools/tinytest-codegen.py) > $@ - -$(BUILD)/tinytest.o: - $(Q)$(CC) $(CFLAGS) -DNO_FORKING -o $@ -c $(TINYTEST)/tinytest.c - ## `$(LD)` doesn't seem to like `--specs` for some reason, but we can just use `$(CC)` here. $(BUILD)/firmware.elf: $(OBJ_COMMON) $(OBJ_RUN) $(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) $(Q)$(SIZE) $@ -$(BUILD)/firmware-test.elf: $(OBJ_COMMON) $(OBJ_TEST) - $(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) - $(Q)$(SIZE) $@ - include $(TOP)/py/mkrules.mk diff --git a/ports/qemu-arm/Makefile.test b/ports/qemu-arm/Makefile.test new file mode 100644 index 0000000000..a9aace6d07 --- /dev/null +++ b/ports/qemu-arm/Makefile.test @@ -0,0 +1,24 @@ +LIB_SRC_C = lib/upytesthelper/upytesthelper.c + +include Makefile + +CFLAGS += -DTEST + +.PHONY: $(BUILD)/genhdr/tests.h + +$(BUILD)/test_main.o: $(BUILD)/genhdr/tests.h +$(BUILD)/genhdr/tests.h: + (cd $(TOP)/tests; ./run-tests --write-exp) + $(Q)echo "Generating $@";(cd $(TOP)/tests; ../tools/tinytest-codegen.py) > $@ + +$(BUILD)/tinytest.o: + $(Q)$(CC) $(CFLAGS) -DNO_FORKING -o $@ -c $(TINYTEST)/tinytest.c + +$(BUILD)/firmware-test.elf: $(OBJ_COMMON) $(OBJ_TEST) + $(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) + $(Q)$(SIZE) $@ + +test: $(BUILD)/firmware-test.elf + qemu-system-arm -machine integratorcp -cpu cortex-m3 -nographic -monitor null -serial null -semihosting -kernel $(BUILD)/firmware-test.elf > $(BUILD)/console.out + $(Q)tail -n2 $(BUILD)/console.out + $(Q)tail -n1 $(BUILD)/console.out | grep -q "status: 0" diff --git a/ports/qemu-arm/README.md b/ports/qemu-arm/README.md index 0cf93c7d56..4f1e79b101 100644 --- a/ports/qemu-arm/README.md +++ b/ports/qemu-arm/README.md @@ -21,3 +21,7 @@ toolchain and not with CodeSourcery toolchain. You will need to modify The difference is that CodeSourcery needs `-T generic-m-hosted.ld` while ARM's version requires `--specs=nano.specs --specs=rdimon.specs` to be passed to the linker. + +To build and run image with builtin testsuite: + + make -f Makefile.test test diff --git a/ports/qemu-arm/mpconfigport.h b/ports/qemu-arm/mpconfigport.h index 51706b9277..5d86191988 100644 --- a/ports/qemu-arm/mpconfigport.h +++ b/ports/qemu-arm/mpconfigport.h @@ -17,6 +17,7 @@ #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) #define MICROPY_CAN_OVERRIDE_BUILTINS (1) +#define MICROPY_WARNINGS (1) #define MICROPY_PY_ALL_SPECIAL_METHODS (1) #define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) @@ -69,3 +70,9 @@ extern const struct _mp_obj_module_t mp_module_uos; // We need to provide a declaration/definition of alloca() #include + +#ifdef TEST +#include "lib/upytesthelper/upytesthelper.h" +#undef MP_PLAT_PRINT_STRN +#define MP_PLAT_PRINT_STRN(str, len) upytest_output(str, len) +#endif diff --git a/ports/qemu-arm/test_main.c b/ports/qemu-arm/test_main.c index acac66e6aa..926478ea1b 100644 --- a/ports/qemu-arm/test_main.c +++ b/ports/qemu-arm/test_main.c @@ -17,41 +17,13 @@ #define HEAP_SIZE (128 * 1024) STATIC void *heap; -void do_str(const char *src); -inline void do_str(const char *src) { - gc_init(heap, (char*)heap + HEAP_SIZE); - mp_init(); - - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); - qstr source_name = lex->source_name; - mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); - mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, false); - mp_call_function_0(module_fun); - nlr_pop(); - } else { - mp_obj_t exc = (mp_obj_t)nlr.ret_val; - if (mp_obj_is_subclass_fast(mp_obj_get_type(exc), &mp_type_SystemExit)) { - // Assume that sys.exit() is called to skip the test. - // TODO: That can be always true, we should set up convention to - // use specific exit code as skip indicator. - tinytest_set_test_skipped_(); - goto end; - } - mp_obj_print_exception(&mp_plat_print, exc); - tt_abort_msg("Uncaught exception"); - } -end: - mp_deinit(); -} - #include "genhdr/tests.h" int main() { mp_stack_ctrl_init(); mp_stack_set_limit(10240); heap = malloc(HEAP_SIZE); + upytest_set_heap(heap, (char*)heap + HEAP_SIZE); int r = tinytest_main(0, NULL, groups); printf("status: %d\n", r); return r; From 8462f167dcc7accb0b4329ce2ea57d4c400b29ee Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 11 Dec 2017 20:22:31 +0200 Subject: [PATCH 157/828] .travis.yml: Update for qemu-arm's testing moved to Makefile.test. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fd23a37072..4a9d238ab9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,7 +37,7 @@ script: - make -C ports/unix - make -C ports/unix nanbox - make -C ports/bare-arm - - make -C ports/qemu-arm test + - make -C ports/qemu-arm -f Makefile.test test - make -C ports/stm32 - make -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1 - make -C ports/stm32 BOARD=STM32F769DISC From 3f6d3ccc11866ea6f84fa43fb50ac9fe5a171fe8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 13 Dec 2017 18:33:39 +1100 Subject: [PATCH 158/828] stm32/usbdev: Pass thru correct val for SCSI PreventAllowMediumRemoval. This value is "1" when the medium should not be removed, "0" otherwise. --- ports/stm32/usbdev/class/src/usbd_msc_scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/usbdev/class/src/usbd_msc_scsi.c b/ports/stm32/usbdev/class/src/usbd_msc_scsi.c index 50cd5b9715..b5363e2d4b 100644 --- a/ports/stm32/usbdev/class/src/usbd_msc_scsi.c +++ b/ports/stm32/usbdev/class/src/usbd_msc_scsi.c @@ -481,7 +481,7 @@ static int8_t SCSI_AllowMediumRemoval(USBD_HandleTypeDef *pdev, uint8_t lun, ui { USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; hmsc->bot_data_length = 0; - hmsc->bdev_ops->PreventAllowMediumRemoval(lun, params[0]); + hmsc->bdev_ops->PreventAllowMediumRemoval(lun, params[4]); return 0; } From 1b223a42bf79640d37567c4f427767ee97d45897 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 13 Dec 2017 22:22:57 +1100 Subject: [PATCH 159/828] extmod/modure: Add cast to workaround bug in MSVC. --- extmod/modure.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extmod/modure.c b/extmod/modure.c index d0180881d3..31c2b98647 100644 --- a/extmod/modure.c +++ b/extmod/modure.c @@ -165,7 +165,8 @@ STATIC mp_obj_t re_split(size_t n_args, const mp_obj_t *args) { break; } } - mp_local_free(caps); + // cast is a workaround for a bug in msvc (see above) + mp_local_free((char**)caps); mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte*)subj.begin, subj.end - subj.begin); mp_obj_list_append(retval, s); From 334934ee972537d9628b9cf4f53bec952c29dcdb Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 13 Dec 2017 18:01:35 +0200 Subject: [PATCH 160/828] tests/run-tests: Add --list-tests switch. Lists tests to be executed, subject to all other filters requested. This options would be useful e.g. for scripts like tools/tinytest-codegen.py, which currently contains hardcoded filters for particular a particular target and can't work for multiple targets. --- tests/run-tests | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/run-tests b/tests/run-tests index 08a92a14fa..45d988b251 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -380,6 +380,10 @@ def run_tests(pyb, tests, args, base_path="."): skipped_tests.append(test_name) continue + if args.list_tests: + print(test_file) + continue + # get expected output test_file_expected = test_file + '.exp' if os.path.isfile(test_file_expected): @@ -430,6 +434,9 @@ def run_tests(pyb, tests, args, base_path="."): test_count += 1 + if args.list_tests: + return True + print("{} tests performed ({} individual testcases)".format(test_count, testcase_count)) print("{} tests passed".format(passed_count)) @@ -451,6 +458,7 @@ def main(): cmd_parser.add_argument('-p', '--password', default='python', help='the telnet login password') cmd_parser.add_argument('-d', '--test-dirs', nargs='*', help='input test directories (if no files given)') cmd_parser.add_argument('--write-exp', action='store_true', help='save .exp files to run tests w/o CPython') + cmd_parser.add_argument('--list-tests', action='store_true', help='list tests instead of running them') cmd_parser.add_argument('--emit', default='bytecode', help='MicroPython emitter to use (bytecode or native)') cmd_parser.add_argument('--heapsize', help='heapsize to use (use default if not specified)') cmd_parser.add_argument('--via-mpy', action='store_true', help='compile .py files to .mpy first') @@ -459,12 +467,12 @@ def main(): args = cmd_parser.parse_args() EXTERNAL_TARGETS = ('pyboard', 'wipy', 'esp8266', 'minimal') - if args.target in EXTERNAL_TARGETS: + if args.target == 'unix' or args.list_tests: + pyb = None + elif args.target in EXTERNAL_TARGETS: import pyboard pyb = pyboard.Pyboard(args.device, args.baudrate, args.user, args.password) pyb.enter_raw_repl() - elif args.target == 'unix': - pyb = None else: raise ValueError('target must be either %s or unix' % ", ".join(EXTERNAL_TARGETS)) From 43141ddb55c715e90b60d2fa2d9d5e01cc66b511 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 13 Dec 2017 18:32:25 +0200 Subject: [PATCH 161/828] tools/tinytest-codegen: Take --target= option for test set selection. Gets passed to run-tests --list-tests to get actual list of tests to use. If --target= is not given, legacy set hardcoded in tinytest-codegen itself is used. Also, get rid of tinytest test groups - they aren't really used for anything, and only complicate processing. Besides, one of the next step is to limit number of tests per a generated file to control the binary size, which also will require "flat" list of tests. --- tools/tinytest-codegen.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/tools/tinytest-codegen.py b/tools/tinytest-codegen.py index d7761cd5ad..c6ba1867af 100755 --- a/tools/tinytest-codegen.py +++ b/tools/tinytest-codegen.py @@ -3,6 +3,8 @@ import os, sys from glob import glob from re import sub +import argparse + def escape(s): s = s.decode() @@ -17,7 +19,7 @@ def escape(s): return "\"\"\n\"{}\"".format(''.join([lookup[x] if x in lookup else x for x in s])) def chew_filename(t): - return { 'func': "test_{}_fn".format(sub(r'/|\.|-', '_', t)), 'desc': t.split('/')[1] } + return { 'func': "test_{}_fn".format(sub(r'/|\.|-', '_', t)), 'desc': t } def script_to_map(test_file): r = {"name": chew_filename(test_file)["func"]} @@ -47,7 +49,7 @@ testgroup_struct = ( "struct testgroup_t groups[] = {{\n{body}\n END_OF_GROUPS\n}};" ) testgroup_member = ( - " {{ \"{name}/\", {name}_tests }}," + " {{ \"{name}\", {name}_tests }}," ) ## XXX: may be we could have `--without ` argument... @@ -82,14 +84,24 @@ exclude_tests = ( ) output = [] +tests = [] -for group in test_dirs: - tests = [test for test in glob('{}/*.py'.format(group)) if test not in exclude_tests] - output.extend([test_function.format(**script_to_map(test)) for test in tests]) - testcase_members = [testcase_member.format(**chew_filename(test)) for test in tests] - output.append(testcase_struct.format(name=group, body='\n'.join(testcase_members))) +argparser = argparse.ArgumentParser(description='Convert native MicroPython tests to tinytest/upytesthelper C code') +argparser.add_argument('--target', help='the target platform') +args = argparser.parse_args() -testgroup_members = [testgroup_member.format(name=group) for group in test_dirs] +if not args.target: + for group in test_dirs: + tests += [test for test in glob('{}/*.py'.format(group)) if test not in exclude_tests] +else: + for l in os.popen("./run-tests --list-tests --target=%s" % args.target, "r"): + tests.append(l.rstrip()) + +output.extend([test_function.format(**script_to_map(test)) for test in tests]) +testcase_members = [testcase_member.format(**chew_filename(test)) for test in tests] +output.append(testcase_struct.format(name="", body='\n'.join(testcase_members))) + +testgroup_members = [testgroup_member.format(name=group) for group in [""]] output.append(testgroup_struct.format(body='\n'.join(testgroup_members))) From bb516af1eb97d0c24fa12b00bfde196b3db94c66 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 14 Dec 2017 10:08:37 +1100 Subject: [PATCH 162/828] tools/pydfu.py: Call set_configuration() on fresh USB device object. This call is required before using the device (some operating systems don't need it but others do). Fixes issue #3476. --- tools/pydfu.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/pydfu.py b/tools/pydfu.py index 8c0220de87..4296f07bfb 100755 --- a/tools/pydfu.py +++ b/tools/pydfu.py @@ -81,6 +81,7 @@ def init(): if len(devices) > 1: raise ValueError("Multiple DFU devices found") __dev = devices[0] + __dev.set_configuration() # Claim DFU interface usb.util.claim_interface(__dev, __DFU_INTERFACE) From badaf3ecfe5d0c8158debf4bd0cb1458016c77f4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 14 Dec 2017 10:40:35 +1100 Subject: [PATCH 163/828] esp8266/machine_hspi: After an SPI write wait for last byte to transfer. Because otherwise the function can return with data still waiting to be clocked out, and CS might then be disabled before the SPI transaction is complete. Fixes issue #3487. --- ports/esp8266/machine_hspi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/esp8266/machine_hspi.c b/ports/esp8266/machine_hspi.c index 9fd0f48682..ff77282911 100644 --- a/ports/esp8266/machine_hspi.c +++ b/ports/esp8266/machine_hspi.c @@ -65,6 +65,9 @@ STATIC void machine_hspi_transfer(mp_obj_base_t *self_in, size_t len, const uint spi_tx8fast(HSPI, src[i]); ++i; } + // wait for SPI transaction to complete + while (spi_busy(HSPI)) { + } } else { // we need to read and write data From 36f79523abe8d79fec1cc7af41e8e96e8ceb2cc4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 14 Dec 2017 12:25:30 +1100 Subject: [PATCH 164/828] tests: Add tests to improve coverage of py/objtype.c. --- tests/basics/class_inherit_mul.py | 5 +++++ tests/basics/class_super_multinherit.py | 16 ++++++++++++++++ tests/basics/sys_getsizeof.py | 15 +++++++++++++++ tests/misc/non_compliant.py | 15 +++++++++++++++ tests/misc/non_compliant.py.exp | 2 ++ 5 files changed, 53 insertions(+) create mode 100644 tests/basics/class_super_multinherit.py create mode 100644 tests/basics/sys_getsizeof.py diff --git a/tests/basics/class_inherit_mul.py b/tests/basics/class_inherit_mul.py index 23476132ba..4a43a7f410 100644 --- a/tests/basics/class_inherit_mul.py +++ b/tests/basics/class_inherit_mul.py @@ -1,3 +1,5 @@ +# test multiple inheritance of user classes + class A: def __init__(self, x): print('A init', x) @@ -30,6 +32,9 @@ class Sub(A, B): def g(self): print(self.x) +print(issubclass(Sub, A)) +print(issubclass(Sub, B)) + o = Sub() print(o.x) o.f() diff --git a/tests/basics/class_super_multinherit.py b/tests/basics/class_super_multinherit.py new file mode 100644 index 0000000000..642a73ce1a --- /dev/null +++ b/tests/basics/class_super_multinherit.py @@ -0,0 +1,16 @@ +# test super with multiple inheritance + +class A: + def foo(self): + print('A.foo') + +class B: + def foo(self): + print('B.foo') + +class C(A, B): + def foo(self): + print('C.foo') + super().foo() + +C().foo() diff --git a/tests/basics/sys_getsizeof.py b/tests/basics/sys_getsizeof.py new file mode 100644 index 0000000000..d16eb1561a --- /dev/null +++ b/tests/basics/sys_getsizeof.py @@ -0,0 +1,15 @@ +# test sys.getsizeof() function + +import sys +try: + sys.getsizeof +except AttributeError: + print('SKIP') + raise SystemExit + +print(sys.getsizeof([1, 2]) >= 2) +print(sys.getsizeof({1: 2}) >= 2) + +class A: + pass +print(sys.getsizeof(A()) > 0) diff --git a/tests/misc/non_compliant.py b/tests/misc/non_compliant.py index 152633c3b7..31129f0759 100644 --- a/tests/misc/non_compliant.py +++ b/tests/misc/non_compliant.py @@ -124,3 +124,18 @@ try: f.x = 1 except AttributeError: print('AttributeError') + +# can't call a function type (ie make new instances of a function) +try: + type(f)() +except TypeError: + print('TypeError') + +# test when object explicitly listed at not-last position in parent tuple +# this is not compliant with CPython because of illegal MRO +class A: + def foo(self): + print('A.foo') +class B(object, A): + pass +B().foo() diff --git a/tests/misc/non_compliant.py.exp b/tests/misc/non_compliant.py.exp index 9c157fd5bd..061e3fcc87 100644 --- a/tests/misc/non_compliant.py.exp +++ b/tests/misc/non_compliant.py.exp @@ -18,3 +18,5 @@ b'\x01\x02' b'\x01\x00' NotImplementedError AttributeError +TypeError +A.foo From 34247465c34113bb26f6c9582ea31f31b0ea0d1b Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Sat, 15 Jul 2017 15:53:47 +0200 Subject: [PATCH 165/828] extmod/modframebuf: Add 2-bit color format (GS2_HMSB). This format is used in 2-color LED matrices and in e-ink displays like SSD1606. --- docs/library/framebuf.rst | 4 +++ extmod/modframebuf.c | 30 +++++++++++++++++ tests/extmod/framebuf2.py | 62 +++++++++++++++++++++++++++++++++++ tests/extmod/framebuf2.py.exp | 57 ++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+) create mode 100644 tests/extmod/framebuf2.py create mode 100644 tests/extmod/framebuf2.py.exp diff --git a/docs/library/framebuf.rst b/docs/library/framebuf.rst index 74c9f85649..4f0026e380 100644 --- a/docs/library/framebuf.rst +++ b/docs/library/framebuf.rst @@ -148,6 +148,10 @@ Constants Red Green Blue (16-bit, 5+6+5) color format +.. data:: framebuf.GS2_HMSB + + Grayscale (2-bit) color format + .. data:: framebuf.GS4_HMSB Grayscale (4-bit) color format diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c index 20e40d5791..f2dc4e858e 100644 --- a/extmod/modframebuf.c +++ b/extmod/modframebuf.c @@ -54,6 +54,7 @@ typedef struct _mp_framebuf_p_t { // constants for formats #define FRAMEBUF_MVLSB (0) #define FRAMEBUF_RGB565 (1) +#define FRAMEBUF_GS2_HMSB (5) #define FRAMEBUF_GS4_HMSB (2) #define FRAMEBUF_MHLSB (3) #define FRAMEBUF_MHMSB (4) @@ -130,6 +131,30 @@ STATIC void rgb565_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, i } } +// Functions for GS2_HMSB format + +STATIC void gs2_hmsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { + uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride) >> 2]; + uint8_t shift = (x & 0x3) << 1; + uint8_t mask = 0x3 << shift; + uint8_t color = (col & 0x3) << shift; + *pixel = color | (*pixel & (~mask)); +} + +STATIC uint32_t gs2_hmsb_getpixel(const mp_obj_framebuf_t *fb, int x, int y) { + uint8_t pixel = ((uint8_t*)fb->buf)[(x + y * fb->stride) >> 2]; + uint8_t shift = (x & 0x3) << 1; + return (pixel >> shift) & 0x3; +} + +STATIC void gs2_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { + for (int xx=x; xx < x+w; xx++) { + for (int yy=y; yy < y+h; yy++) { + gs2_hmsb_setpixel(fb, xx, yy, col); + } + } +} + // Functions for GS4_HMSB format STATIC void gs4_hmsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { @@ -184,6 +209,7 @@ STATIC void gs4_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, STATIC mp_framebuf_p_t formats[] = { [FRAMEBUF_MVLSB] = {mvlsb_setpixel, mvlsb_getpixel, mvlsb_fill_rect}, [FRAMEBUF_RGB565] = {rgb565_setpixel, rgb565_getpixel, rgb565_fill_rect}, + [FRAMEBUF_GS2_HMSB] = {gs2_hmsb_setpixel, gs2_hmsb_getpixel, gs2_hmsb_fill_rect}, [FRAMEBUF_GS4_HMSB] = {gs4_hmsb_setpixel, gs4_hmsb_getpixel, gs4_hmsb_fill_rect}, [FRAMEBUF_MHLSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect}, [FRAMEBUF_MHMSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect}, @@ -240,6 +266,9 @@ STATIC mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size case FRAMEBUF_MHMSB: o->stride = (o->stride + 7) & ~7; break; + case FRAMEBUF_GS2_HMSB: + o->stride = (o->stride + 3) & ~3; + break; case FRAMEBUF_GS4_HMSB: o->stride = (o->stride + 1) & ~1; break; @@ -579,6 +608,7 @@ STATIC const mp_rom_map_elem_t framebuf_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_MVLSB), MP_ROM_INT(FRAMEBUF_MVLSB) }, { MP_ROM_QSTR(MP_QSTR_MONO_VLSB), MP_ROM_INT(FRAMEBUF_MVLSB) }, { MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_INT(FRAMEBUF_RGB565) }, + { MP_ROM_QSTR(MP_QSTR_GS2_HMSB), MP_ROM_INT(FRAMEBUF_GS2_HMSB) }, { MP_ROM_QSTR(MP_QSTR_GS4_HMSB), MP_ROM_INT(FRAMEBUF_GS4_HMSB) }, { MP_ROM_QSTR(MP_QSTR_MONO_HLSB), MP_ROM_INT(FRAMEBUF_MHLSB) }, { MP_ROM_QSTR(MP_QSTR_MONO_HMSB), MP_ROM_INT(FRAMEBUF_MHMSB) }, diff --git a/tests/extmod/framebuf2.py b/tests/extmod/framebuf2.py new file mode 100644 index 0000000000..a313170eb5 --- /dev/null +++ b/tests/extmod/framebuf2.py @@ -0,0 +1,62 @@ +try: + import framebuf +except ImportError: + print("SKIP") + raise SystemExit + +def printbuf(): + print("--8<--") + for y in range(h): + for x in range(w): + print('%u' % ((buf[(x + y * w) // 4] >> ((x & 3) << 1)) & 3), end='') + print() + print("-->8--") + +w = 8 +h = 5 +buf = bytearray(w * h // 4) +fbuf = framebuf.FrameBuffer(buf, w, h, framebuf.GS2_HMSB) + +# fill +fbuf.fill(3) +printbuf() +fbuf.fill(0) +printbuf() + +# put pixel +fbuf.pixel(0, 0, 1) +fbuf.pixel(3, 0, 2) +fbuf.pixel(0, 4, 3) +fbuf.pixel(3, 4, 2) +printbuf() + +# get pixel +print(fbuf.pixel(0, 4), fbuf.pixel(1, 1)) + +# scroll +fbuf.fill(0) +fbuf.pixel(2, 2, 3) +printbuf() +fbuf.scroll(0, 1) +printbuf() +fbuf.scroll(1, 0) +printbuf() +fbuf.scroll(-1, -2) +printbuf() + +w2 = 2 +h2 = 3 +buf2 = bytearray(w2 * h2 // 4) +fbuf2 = framebuf.FrameBuffer(buf2, w2, h2, framebuf.GS2_HMSB) + +# blit +fbuf2.fill(0) +fbuf2.pixel(0, 0, 1) +fbuf2.pixel(0, 2, 2) +fbuf2.pixel(1, 0, 1) +fbuf2.pixel(1, 2, 2) +fbuf.fill(3) +fbuf.blit(fbuf2, 3, 3, 0) +fbuf.blit(fbuf2, -1, -1, 0) +fbuf.blit(fbuf2, 16, 16, 0) +printbuf() diff --git a/tests/extmod/framebuf2.py.exp b/tests/extmod/framebuf2.py.exp new file mode 100644 index 0000000000..c53e518a6e --- /dev/null +++ b/tests/extmod/framebuf2.py.exp @@ -0,0 +1,57 @@ +--8<-- +33333333 +33333333 +33333333 +33333333 +33333333 +-->8-- +--8<-- +00000000 +00000000 +00000000 +00000000 +00000000 +-->8-- +--8<-- +10020000 +00000000 +00000000 +00000000 +30020000 +-->8-- +3 0 +--8<-- +00000000 +00000000 +00300000 +00000000 +00000000 +-->8-- +--8<-- +00000000 +00000000 +00000000 +00300000 +00000000 +-->8-- +--8<-- +00000000 +00000000 +00000000 +00030000 +00000000 +-->8-- +--8<-- +00000000 +00300000 +00000000 +00030000 +00000000 +-->8-- +--8<-- +33333333 +23333333 +33333333 +33311333 +33333333 +-->8-- From 46b35356e1727365dd5a33fcf3a722fda82c8b08 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 14 Dec 2017 17:36:13 +1100 Subject: [PATCH 166/828] extmod/modframebuf: Add 8-bit greyscale format (GS8). --- docs/library/framebuf.rst | 4 ++++ extmod/modframebuf.c | 24 ++++++++++++++++++++++++ tests/extmod/framebuf8.py | 32 ++++++++++++++++++++++++++++++++ tests/extmod/framebuf8.py.exp | 15 +++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 tests/extmod/framebuf8.py create mode 100644 tests/extmod/framebuf8.py.exp diff --git a/docs/library/framebuf.rst b/docs/library/framebuf.rst index 4f0026e380..ed4b78ab14 100644 --- a/docs/library/framebuf.rst +++ b/docs/library/framebuf.rst @@ -155,3 +155,7 @@ Constants .. data:: framebuf.GS4_HMSB Grayscale (4-bit) color format + +.. data:: framebuf.GS8 + + Grayscale (8-bit) color format diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c index f2dc4e858e..a7f6ba905f 100644 --- a/extmod/modframebuf.c +++ b/extmod/modframebuf.c @@ -56,6 +56,7 @@ typedef struct _mp_framebuf_p_t { #define FRAMEBUF_RGB565 (1) #define FRAMEBUF_GS2_HMSB (5) #define FRAMEBUF_GS4_HMSB (2) +#define FRAMEBUF_GS8 (6) #define FRAMEBUF_MHLSB (3) #define FRAMEBUF_MHMSB (4) @@ -206,11 +207,31 @@ STATIC void gs4_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, } } +// Functions for GS8 format + +STATIC void gs8_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { + uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride)]; + *pixel = col & 0xff; +} + +STATIC uint32_t gs8_getpixel(const mp_obj_framebuf_t *fb, int x, int y) { + return ((uint8_t*)fb->buf)[(x + y * fb->stride)]; +} + +STATIC void gs8_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { + uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride)]; + while (h--) { + memset(pixel, col, w); + pixel += fb->stride; + } +} + STATIC mp_framebuf_p_t formats[] = { [FRAMEBUF_MVLSB] = {mvlsb_setpixel, mvlsb_getpixel, mvlsb_fill_rect}, [FRAMEBUF_RGB565] = {rgb565_setpixel, rgb565_getpixel, rgb565_fill_rect}, [FRAMEBUF_GS2_HMSB] = {gs2_hmsb_setpixel, gs2_hmsb_getpixel, gs2_hmsb_fill_rect}, [FRAMEBUF_GS4_HMSB] = {gs4_hmsb_setpixel, gs4_hmsb_getpixel, gs4_hmsb_fill_rect}, + [FRAMEBUF_GS8] = {gs8_setpixel, gs8_getpixel, gs8_fill_rect}, [FRAMEBUF_MHLSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect}, [FRAMEBUF_MHMSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect}, }; @@ -272,6 +293,8 @@ STATIC mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size case FRAMEBUF_GS4_HMSB: o->stride = (o->stride + 1) & ~1; break; + case FRAMEBUF_GS8: + break; default: mp_raise_ValueError("invalid format"); } @@ -610,6 +633,7 @@ STATIC const mp_rom_map_elem_t framebuf_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_INT(FRAMEBUF_RGB565) }, { MP_ROM_QSTR(MP_QSTR_GS2_HMSB), MP_ROM_INT(FRAMEBUF_GS2_HMSB) }, { MP_ROM_QSTR(MP_QSTR_GS4_HMSB), MP_ROM_INT(FRAMEBUF_GS4_HMSB) }, + { MP_ROM_QSTR(MP_QSTR_GS8), MP_ROM_INT(FRAMEBUF_GS8) }, { MP_ROM_QSTR(MP_QSTR_MONO_HLSB), MP_ROM_INT(FRAMEBUF_MHLSB) }, { MP_ROM_QSTR(MP_QSTR_MONO_HMSB), MP_ROM_INT(FRAMEBUF_MHMSB) }, }; diff --git a/tests/extmod/framebuf8.py b/tests/extmod/framebuf8.py new file mode 100644 index 0000000000..b6899aae91 --- /dev/null +++ b/tests/extmod/framebuf8.py @@ -0,0 +1,32 @@ +try: + import framebuf +except ImportError: + print("SKIP") + raise SystemExit + +def printbuf(): + print("--8<--") + for y in range(h): + for x in range(w): + print('%02x' % buf[(x + y * w)], end='') + print() + print("-->8--") + +w = 8 +h = 5 +buf = bytearray(w * h) +fbuf = framebuf.FrameBuffer(buf, w, h, framebuf.GS8) + +# fill +fbuf.fill(0x55) +printbuf() + +# put pixel +fbuf.pixel(0, 0, 0x11) +fbuf.pixel(w - 1, 0, 0x22) +fbuf.pixel(0, h - 1, 0x33) +fbuf.pixel(w - 1, h - 1, 0xff) +printbuf() + +# get pixel +print(hex(fbuf.pixel(0, h - 1)), hex(fbuf.pixel(1, 1))) diff --git a/tests/extmod/framebuf8.py.exp b/tests/extmod/framebuf8.py.exp new file mode 100644 index 0000000000..01d8976fec --- /dev/null +++ b/tests/extmod/framebuf8.py.exp @@ -0,0 +1,15 @@ +--8<-- +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +-->8-- +--8<-- +1155555555555522 +5555555555555555 +5555555555555555 +5555555555555555 +33555555555555ff +-->8-- +0x33 0x55 From 8d11fc0bc4c0b9d569a343a785bf079d6441eb16 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 14 Dec 2017 10:32:34 +0200 Subject: [PATCH 167/828] tests/run-tests: minimal: Exclude recently added subclass_native_init.py. It relies on MICROPY_CPYTHON_COMPAT being defined. --- tests/run-tests | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-tests b/tests/run-tests index 45d988b251..35b609612f 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -313,6 +313,7 @@ def run_tests(pyb, tests, args, base_path="."): skip_tests.add('misc/rge_sm.py') # too large elif args.target == 'minimal': skip_tests.add('basics/class_inplace_op.py') # all special methods not supported + skip_tests.add('basics/subclass_native_init.py')# native subclassing corner cases not support skip_tests.add('misc/rge_sm.py') # too large skip_tests.add('micropython/opt_level.py') # don't assume line numbers are stored skip_tests.add('float/float_parse.py') # minor parsing artifacts with 32-bit floats From aaeb70b7b7a670e3beb51fc2efa956d4de51a05a Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 14 Dec 2017 12:11:17 +0200 Subject: [PATCH 168/828] tests/run-tests: Fix handling of --list-tests wrt skipped tests. "skip " message could leak before. --- tests/run-tests | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/run-tests b/tests/run-tests index 35b609612f..2330b7df0a 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -376,15 +376,16 @@ def run_tests(pyb, tests, args, base_path="."): skip_it |= skip_const and is_const skip_it |= skip_revops and test_name.startswith("class_reverse_op") + if args.list_tests: + if not skip_it: + print(test_file) + continue + if skip_it: print("skip ", test_file) skipped_tests.append(test_name) continue - if args.list_tests: - print(test_file) - continue - # get expected output test_file_expected = test_file + '.exp' if os.path.isfile(test_file_expected): From 64bb32d87f35531fc003493af9b4f526b19e68f3 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 14 Dec 2017 12:26:10 +0200 Subject: [PATCH 169/828] tests/run-tests: Add composable --include and --exclude options. The idea that --list-tests would be enough to produce list of tests for tinytest-codegen didn't work, because normal run-tests processing heavily relies on dynamic target capabilities discovery, and test filtering happens as the result of that. So, approach the issue from different end - allow to specify arbitrary filtering criteria as run-tests arguments. This way, specific filters will be still hardcoded, but at least on a particular target's side, instead of constant patching tinytest-codegen and/or run-tests. --- tests/run-tests | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/tests/run-tests b/tests/run-tests index 2330b7df0a..b5f19be479 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -358,6 +358,16 @@ def run_tests(pyb, tests, args, base_path="."): for test_file in tests: test_file = test_file.replace('\\', '/') + + if args.filters: + # Default verdict is the opposit of the first action + verdict = "include" if args.filters[0][0] == "exclude" else "exclude" + for action, pat in args.filters: + if pat.search(test_file): + verdict = action + if verdict == "exclude": + continue + test_basename = os.path.basename(test_file) test_name = os.path.splitext(test_basename)[0] is_native = test_name.startswith("native_") or test_name.startswith("viper_") @@ -451,14 +461,42 @@ def run_tests(pyb, tests, args, base_path="."): # all tests succeeded return True + +class append_filter(argparse.Action): + + def __init__(self, option_strings, dest, **kwargs): + super().__init__(option_strings, dest, default=[], **kwargs) + + def __call__(self, parser, args, value, option): + if not hasattr(args, self.dest): + args.filters = [] + if option.startswith(("-e", "--e")): + option = "exclude" + else: + option = "include" + args.filters.append((option, re.compile(value))) + + def main(): - cmd_parser = argparse.ArgumentParser(description='Run tests for MicroPython.') + cmd_parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description='Run and manage tests for MicroPython.', + epilog='''\ +Options -i and -e can be multiple and processed in the order given. Regex +"search" (vs "match") operation is used. An action (include/exclude) of +the last matching regex is used: + run-tests -i async - exclude all, then include tests containg "async" anywhere + run-tests -e '/big.+int' - include all, then exclude by regex + run-tests -e async -i async_foo - include all, exclude async, yet still include async_foo +''') cmd_parser.add_argument('--target', default='unix', help='the target platform') cmd_parser.add_argument('--device', default='/dev/ttyACM0', help='the serial device or the IP address of the pyboard') cmd_parser.add_argument('-b', '--baudrate', default=115200, help='the baud rate of the serial device') cmd_parser.add_argument('-u', '--user', default='micro', help='the telnet login username') cmd_parser.add_argument('-p', '--password', default='python', help='the telnet login password') cmd_parser.add_argument('-d', '--test-dirs', nargs='*', help='input test directories (if no files given)') + cmd_parser.add_argument('-e', '--exclude', action=append_filter, metavar='REGEX', dest='filters', help='exclude test by regex on path/name.py') + cmd_parser.add_argument('-i', '--include', action=append_filter, metavar='REGEX', dest='filters', help='include test by regex on path/name.py') cmd_parser.add_argument('--write-exp', action='store_true', help='save .exp files to run tests w/o CPython') cmd_parser.add_argument('--list-tests', action='store_true', help='list tests instead of running them') cmd_parser.add_argument('--emit', default='bytecode', help='MicroPython emitter to use (bytecode or native)') From 325d0fc74ba9634f89f6535210944ccdd635a995 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 14 Dec 2017 12:26:59 +0200 Subject: [PATCH 170/828] tools/tinytest-codegen: Add --stdin switch instead of recently added --target. Instead of passing thru more and more options from tinytest-codegen to run-tests --list-tests, pipe output of run-tests --list-tests into tinytest-codegen. --- tools/tinytest-codegen.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/tinytest-codegen.py b/tools/tinytest-codegen.py index c6ba1867af..5339972cd4 100755 --- a/tools/tinytest-codegen.py +++ b/tools/tinytest-codegen.py @@ -87,14 +87,14 @@ output = [] tests = [] argparser = argparse.ArgumentParser(description='Convert native MicroPython tests to tinytest/upytesthelper C code') -argparser.add_argument('--target', help='the target platform') +argparser.add_argument('--stdin', action="store_true", help='read list of tests from stdin') args = argparser.parse_args() -if not args.target: +if not args.stdin: for group in test_dirs: tests += [test for test in glob('{}/*.py'.format(group)) if test not in exclude_tests] else: - for l in os.popen("./run-tests --list-tests --target=%s" % args.target, "r"): + for l in sys.stdin: tests.append(l.rstrip()) output.extend([test_function.format(**script_to_map(test)) for test in tests]) From 3233537a1505780ac189031857f0b95d43fb9adb Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 14 Dec 2017 13:36:06 +0200 Subject: [PATCH 171/828] tests/run-tests: Don't test for --target=unix with "pyb is None". If we test for unix target, do that explicitly. pyb var will be None for commands like --list-tests too. --- tests/run-tests | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-tests b/tests/run-tests index b5f19be479..79b3e21126 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -287,14 +287,14 @@ def run_tests(pyb, tests, args, base_path="."): skip_tests.add('cmdline/cmd_parsetree.py') # Some tests shouldn't be run on a PC - if pyb is None: + if args.target == 'unix': # unix build does not have the GIL so can't run thread mutation tests for t in tests: if t.startswith('thread/mutate_'): skip_tests.add(t) # Some tests shouldn't be run on pyboard - if pyb is not None: + if args.target != 'unix': skip_tests.add('basics/exception_chain.py') # warning is not printed skip_tests.add('micropython/meminfo.py') # output is very different to PC output skip_tests.add('extmod/machine_mem.py') # raw memory access not supported From bf73ee114f4085e06181037305599fdfeba59523 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 14 Dec 2017 18:28:10 +0200 Subject: [PATCH 172/828] docs/packages: mpy_bin2res no longer required to create resources. Everything happens automagically with overridden "sdist" from sdist_upip.py. --- docs/reference/packages.rst | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/docs/reference/packages.rst b/docs/reference/packages.rst index d8d198e628..3d05f0b27c 100644 --- a/docs/reference/packages.rst +++ b/docs/reference/packages.rst @@ -259,8 +259,8 @@ an extra intermediate step when packaging application - creation of The idea of this module is to convert binary data to a Python bytes object, and put it into the dictionary, indexed by the resource name. -This conversion is done using ``tools/mpy_bin2res.py`` script from -the MicroPython distribution. +This conversion is done automatically using overridden ``sdist`` command +described in the previous section. Let's trace the complete process using the following example. Suppose your application has the following structure:: @@ -281,17 +281,28 @@ following calls:: pkg_resources.resource_stream(__name__, "data/image.png") You can develop and debug using the `MicroPython Unix port` as usual. -When times come to make a distribution package out of it, you would -need to run following command, with ``my_app/`` being the current -directory (and assuming ``mpy_bin2res.py`` is in your path):: +When time comes to make a distribution package out of it, just use +overridden "sdist" command from sdist_upip.py module as described in +the previous section. - mpy_bin2res.py data/page.html data/image.png +This will create a Python resource module named ``R.py``, based on the +files declared in ``MANIFEST`` or ``MANIFEST.in`` files (any non-``.py`` +file will be considered a resource and added to ``R.py``) - before +proceeding with the normal packaging steps. -This will produce a Python resource module named ``R.py``. Afterwards, -you package the project for distribution as usual (using ``setup.py sdist``). Prepared like this, your application will work both when deployed to filesystem and as frozen bytecode. +If you would like to debug ``R.py`` creation, you can run:: + + python3 setup.py sdist --manifest-only + +Alternatively, you can use tools/mpy_bin2res.py script from the +MicroPython distribution, in which can you will need to pass paths +to all resource files:: + + mpy_bin2res.py data/page.html data/image.png + References ---------- From 448d93a04aff95dd300cf3485eb7e7a74cfdfcbf Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 15 Dec 2017 00:11:02 +0200 Subject: [PATCH 173/828] docs/glossary: micropython-lib: Clarify wording. --- docs/reference/glossary.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reference/glossary.rst b/docs/reference/glossary.rst index 9daf0dc3a1..a6abc8b9da 100644 --- a/docs/reference/glossary.rst +++ b/docs/reference/glossary.rst @@ -95,8 +95,8 @@ Glossary `micropython-lib `_ which provides implementations for many modules from CPython's standard library. However, large subset of these modules require - POSIX-like environment (Linux, MacOS, Windows may be partially - supported), and thus would work or make sense only with + POSIX-like environment (Linux, FreeBSD, MacOS, etc.; Windows may be + partially supported), and thus would work or make sense only with `MicroPython Unix port`. Some subset of modules is however usable for `baremetal` ports too. From cf8e8c29e72ef4871b9d5ab3de32bdaf429c5dbb Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 15 Dec 2017 10:21:10 +1100 Subject: [PATCH 174/828] py/emitglue: Change type of bit-field to explicitly unsigned mp_uint_t. Some compilers can treat enum types as signed, in which case 3 bits is not enough to encode all mp_raw_code_kind_t values. So change the type to mp_uint_t. --- py/emitglue.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/emitglue.h b/py/emitglue.h index 43930333d6..f2a48c5e51 100644 --- a/py/emitglue.h +++ b/py/emitglue.h @@ -40,7 +40,7 @@ typedef enum { } mp_raw_code_kind_t; typedef struct _mp_raw_code_t { - mp_raw_code_kind_t kind : 3; + mp_uint_t kind : 3; // of type mp_raw_code_kind_t mp_uint_t scope_flags : 7; mp_uint_t n_pos_args : 11; union { From 4475f324202e15b98f2f365e33078aebcf0bc5a5 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 15 Dec 2017 11:37:32 +0200 Subject: [PATCH 175/828] tools/tinytest-codegen: Ignore system locale, write output in UTF-8. Way to reproduce a UnicodeEncodeError without this patch: LC_ALL=C tinytest-codegen.py ... --- tools/tinytest-codegen.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/tinytest-codegen.py b/tools/tinytest-codegen.py index 5339972cd4..ad3b3bbec9 100755 --- a/tools/tinytest-codegen.py +++ b/tools/tinytest-codegen.py @@ -106,4 +106,5 @@ testgroup_members = [testgroup_member.format(name=group) for group in [""]] output.append(testgroup_struct.format(body='\n'.join(testgroup_members))) ## XXX: may be we could have `--output ` argument... -print('\n\n'.join(output)) +# Don't depend on what system locale is set, use utf8 encoding. +sys.stdout.buffer.write('\n\n'.join(output).encode('utf8')) From 103eeffcd925891867916c6f7d23dcbb098c59fe Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 15 Dec 2017 12:07:09 +0200 Subject: [PATCH 176/828] tests/run-tests: Skip running feature checks for --list-tests/--write-exp. The whole idea of --list-tests is that we prepare a list of tests to run later, and currently don't have a connection to target board. Similarly for --write-exp - only "python3" binary would be required for this operation, not "micropython". --- tests/run-tests | 76 +++++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/tests/run-tests b/tests/run-tests index 79b3e21126..45cb1a7465 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -211,48 +211,56 @@ def run_tests(pyb, tests, args, base_path="."): skip_async = False skip_const = False skip_revops = False + skip_endian = False + has_complex = True + has_coverage = False - # Check if micropython.native is supported, and skip such tests if it's not - output = run_feature_check(pyb, args, base_path, 'native_check.py') - if output == b'CRASH': - skip_native = True + upy_float_precision = 32 - # Check if arbitrary-precision integers are supported, and skip such tests if it's not - output = run_feature_check(pyb, args, base_path, 'int_big.py') - if output != b'1000000000000000000000000000000000000000000000\n': - skip_int_big = True + # If we're asked to --list-tests, we can't assume that there's a + # connection to target, so we can't run feature checks usefully. + if not (args.list_tests or args.write_exp): + # Check if micropython.native is supported, and skip such tests if it's not + output = run_feature_check(pyb, args, base_path, 'native_check.py') + if output == b'CRASH': + skip_native = True - # Check if set type (and set literals) is supported, and skip such tests if it's not - output = run_feature_check(pyb, args, base_path, 'set_check.py') - if output == b'CRASH': - skip_set_type = True + # Check if arbitrary-precision integers are supported, and skip such tests if it's not + output = run_feature_check(pyb, args, base_path, 'int_big.py') + if output != b'1000000000000000000000000000000000000000000000\n': + skip_int_big = True - # Check if async/await keywords are supported, and skip such tests if it's not - output = run_feature_check(pyb, args, base_path, 'async_check.py') - if output == b'CRASH': - skip_async = True + # Check if set type (and set literals) is supported, and skip such tests if it's not + output = run_feature_check(pyb, args, base_path, 'set_check.py') + if output == b'CRASH': + skip_set_type = True - # Check if const keyword (MicroPython extension) is supported, and skip such tests if it's not - output = run_feature_check(pyb, args, base_path, 'const.py') - if output == b'CRASH': - skip_const = True + # Check if async/await keywords are supported, and skip such tests if it's not + output = run_feature_check(pyb, args, base_path, 'async_check.py') + if output == b'CRASH': + skip_async = True - # Check if __rOP__ special methods are supported, and skip such tests if it's not - output = run_feature_check(pyb, args, base_path, 'reverse_ops.py') - if output == b'TypeError\n': - skip_revops = True + # Check if const keyword (MicroPython extension) is supported, and skip such tests if it's not + output = run_feature_check(pyb, args, base_path, 'const.py') + if output == b'CRASH': + skip_const = True - # Check if emacs repl is supported, and skip such tests if it's not - t = run_feature_check(pyb, args, base_path, 'repl_emacs_check.py') - if not 'True' in str(t, 'ascii'): - skip_tests.add('cmdline/repl_emacs_keys.py') + # Check if __rOP__ special methods are supported, and skip such tests if it's not + output = run_feature_check(pyb, args, base_path, 'reverse_ops.py') + if output == b'TypeError\n': + skip_revops = True - upy_byteorder = run_feature_check(pyb, args, base_path, 'byteorder.py') - upy_float_precision = int(run_feature_check(pyb, args, base_path, 'float.py')) - has_complex = run_feature_check(pyb, args, base_path, 'complex.py') == b'complex\n' - has_coverage = run_feature_check(pyb, args, base_path, 'coverage.py') == b'coverage\n' - cpy_byteorder = subprocess.check_output([CPYTHON3, base_path + '/feature_check/byteorder.py']) - skip_endian = (upy_byteorder != cpy_byteorder) + # Check if emacs repl is supported, and skip such tests if it's not + t = run_feature_check(pyb, args, base_path, 'repl_emacs_check.py') + if not 'True' in str(t, 'ascii'): + skip_tests.add('cmdline/repl_emacs_keys.py') + + upy_byteorder = run_feature_check(pyb, args, base_path, 'byteorder.py') + upy_float_precision = int(run_feature_check(pyb, args, base_path, 'float.py')) + has_complex = run_feature_check(pyb, args, base_path, 'complex.py') == b'complex\n' + has_coverage = run_feature_check(pyb, args, base_path, 'coverage.py') == b'coverage\n' + cpy_byteorder = subprocess.check_output([CPYTHON3, base_path + '/feature_check/byteorder.py']) + skip_endian = (upy_byteorder != cpy_byteorder) # Some tests shouldn't be run under Travis CI if os.getenv('TRAVIS') == 'true': From 6b19520a743ddafcdd1881582d4c90a9ea068610 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 15 Dec 2017 12:10:39 +0200 Subject: [PATCH 177/828] zephyr: Add support for binary with builtin testsuite. If TEST is defined, file it refers to will be used as the testsuite source (should be generated with tools/tinytest-codegen.py). "make-bin-testsuite" script is introduce to build such a binary. --- ports/zephyr/main.c | 15 +++++++++++ ports/zephyr/make-bin-testsuite | 20 +++++++++++++++ ports/zephyr/mpconfigport_bin_testsuite.h | 31 +++++++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100755 ports/zephyr/make-bin-testsuite create mode 100644 ports/zephyr/mpconfigport_bin_testsuite.h diff --git a/ports/zephyr/main.c b/ports/zephyr/main.c index d6ddc65cc2..8c64fdceea 100644 --- a/ports/zephyr/main.c +++ b/ports/zephyr/main.c @@ -41,6 +41,13 @@ #include "lib/utils/pyexec.h" #include "lib/mp-readline/readline.h" +#ifdef TEST +#include "lib/upytesthelper/upytesthelper.h" +#include "lib/tinytest/tinytest.c" +#include "lib/upytesthelper/upytesthelper.c" +#include TEST +#endif + static char *stack_top; static char heap[MICROPY_HEAP_SIZE]; @@ -95,6 +102,14 @@ int real_main(void) { init_zephyr(); + #ifdef TEST + static const char *argv[] = {"test"}; + upytest_set_heap(heap, heap + sizeof(heap)); + int r = tinytest_main(1, argv, groups); + printf("status: %d\n", r); + return 0; + #endif + soft_reset: #if MICROPY_ENABLE_GC gc_init(heap, heap + sizeof(heap)); diff --git a/ports/zephyr/make-bin-testsuite b/ports/zephyr/make-bin-testsuite new file mode 100755 index 0000000000..f6aeb83f8a --- /dev/null +++ b/ports/zephyr/make-bin-testsuite @@ -0,0 +1,20 @@ +#!/bin/sh +# +# This is a wrapper for make to build a binary with builtin testsuite. +# It should be run just like make (i.e. extra vars can be passed on the +# command line, etc.), e.g.: +# +# ./make-bin-testsuite BOARD=qemu_cortex_m3 +# ./make-bin-testsuite BOARD=qemu_cortex_m3 run +# + +(cd ../../tests; ./run-tests --write-exp) +(cd ../../tests; ./run-tests --list-tests --target=minimal \ + -e async -e intbig -e int_big -e builtin_help -e memstats -e bytes_compare3 -e class_reverse_op \ + -e /set -e frozenset -e complex -e const -e native -e viper \ + -e 'float_divmod\.' -e float_parse_doubleprec -e float/true_value -e float/types \ + | ../tools/tinytest-codegen.py --stdin) > bin-testsuite.c + +make \ + CFLAGS_EXTRA='-DMP_CONFIGFILE="" -DTEST=\"bin-testsuite.c\" -DNO_FORKING' \ + "$@" diff --git a/ports/zephyr/mpconfigport_bin_testsuite.h b/ports/zephyr/mpconfigport_bin_testsuite.h new file mode 100644 index 0000000000..684b4f41c2 --- /dev/null +++ b/ports/zephyr/mpconfigport_bin_testsuite.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "mpconfigport.h" + +#ifdef TEST +#include "lib/upytesthelper/upytesthelper.h" +#define MP_PLAT_PRINT_STRN(str, len) upytest_output(str, len) +#endif From dd35fe7ca0e18af0286f89a20e5f743015d3dac5 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 15 Dec 2017 18:17:00 +0200 Subject: [PATCH 178/828] zephyr/prj_base.conf: Bump MAIN_STACK_SIZE to let builtin testsuite run. --- ports/zephyr/prj_base.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr/prj_base.conf b/ports/zephyr/prj_base.conf index 58c65f14de..3858c0a024 100644 --- a/ports/zephyr/prj_base.conf +++ b/ports/zephyr/prj_base.conf @@ -12,7 +12,7 @@ CONFIG_CONSOLE_PUTCHAR_BUFSIZE=128 CONFIG_NEWLIB_LIBC=y CONFIG_FLOAT=y -CONFIG_MAIN_STACK_SIZE=4096 +CONFIG_MAIN_STACK_SIZE=4736 # Networking config CONFIG_NETWORKING=y From f4ed2dfa942339dc1f174e8a83ff0d41073f1972 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 15 Dec 2017 19:41:08 +0200 Subject: [PATCH 179/828] lib/tinytest: Clean up test reporting in the presence of stdout output. tinytest is written with the idea that tests won't write to stdout, so it prints test name witjout newline, then executes test, then writes status. But MicroPython tests write to stdout, so the test output becomes a mess. So, instead print it like: # starting basics/andor.py ... test output ... basics/andor.py: OK --- lib/tinytest/tinytest.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/tinytest/tinytest.c b/lib/tinytest/tinytest.c index 1ef957d31b..01772f3f8e 100644 --- a/lib/tinytest/tinytest.c +++ b/lib/tinytest/tinytest.c @@ -234,8 +234,9 @@ testcase_run_one(const struct testgroup_t *group, return SKIP; } + printf("# starting %s%s\n", group->prefix, testcase->name); if (opt_verbosity>0 && !opt_forked) { - printf("%s%s: ", group->prefix, testcase->name); + //printf("%s%s: ", group->prefix, testcase->name); } else { if (opt_verbosity==0) printf("."); cur_test_prefix = group->prefix; @@ -252,6 +253,7 @@ testcase_run_one(const struct testgroup_t *group, outcome = testcase_run_bare_(testcase); } + printf("%s%s: ", group->prefix, testcase->name); if (outcome == OK) { ++n_ok; if (opt_verbosity>0 && !opt_forked) @@ -263,7 +265,8 @@ testcase_run_one(const struct testgroup_t *group, } else { ++n_bad; if (!opt_forked) - printf("\n [%s FAILED]\n", testcase->name); + //printf("\n [%s FAILED]\n", testcase->name); + puts("FAILED"); } if (opt_forked) { From 63644016669c173190c71d39fb33ad9502fe2b0f Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 21 Oct 2017 12:13:44 +0300 Subject: [PATCH 180/828] py/objgenerator: Allow to pend an exception for next execution. This implements .pend_throw(exc) method, which sets up an exception to be triggered on the next call to generator's .__next__() or .send() method. This is unlike .throw(), which immediately starts to execute the generator to process the exception. This effectively adds Future-like capabilities to generator protocol (exception will be raised in the future). The need for such a method arised to implement uasyncio wait_for() function efficiently (its behavior is clearly "Future" like, and normally would require to introduce an expensive Future wrapper around all native couroutines, like upstream asyncio does). py/objgenerator: pend_throw: Return previous pended value. This effectively allows to store an additional value (not necessary an exception) in a coroutine while it's not being executed. uasyncio has exactly this usecase: to mark a coro waiting in I/O queue (and thus not executed in the normal scheduling queue), for the purpose of implementing wait_for() function (cancellation of such waiting coro by a timeout). --- py/mpconfig.h | 9 +++++++ py/objgenerator.c | 30 ++++++++++++++++++++++-- tests/basics/generator_pend_throw.py | 26 ++++++++++++++++++++ tests/basics/generator_pend_throw.py.exp | 4 ++++ tests/run-tests | 2 +- 5 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 tests/basics/generator_pend_throw.py create mode 100644 tests/basics/generator_pend_throw.py.exp diff --git a/py/mpconfig.h b/py/mpconfig.h index 19bae4f88a..763bb378e0 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -706,6 +706,15 @@ typedef double mp_float_t; #define MICROPY_PY_ASYNC_AWAIT (1) #endif +// Non-standard .pend_throw() method for generators, allowing for +// Future-like behavior with respect to exception handling: an +// exception set with .pend_throw() will activate on the next call +// to generator's .send() or .__next__(). (This is useful to implement +// async schedulers.) +#ifndef MICROPY_PY_GENERATOR_PEND_THROW +#define MICROPY_PY_GENERATOR_PEND_THROW (1) +#endif + // Issue a warning when comparing str and bytes objects #ifndef MICROPY_PY_STR_BYTES_CMP_WARN #define MICROPY_PY_STR_BYTES_CMP_WARN (0) diff --git a/py/objgenerator.c b/py/objgenerator.c index 9a294debb4..8c1260b60f 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2014 Paul Sokolovsky + * Copyright (c) 2014-2017 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -104,7 +104,16 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ mp_raise_TypeError("can't send non-None value to a just-started generator"); } } else { - *self->code_state.sp = send_value; + #if MICROPY_PY_GENERATOR_PEND_THROW + // If exception is pending (set using .pend_throw()), process it now. + if (*self->code_state.sp != mp_const_none) { + throw_value = *self->code_state.sp; + *self->code_state.sp = MP_OBJ_NULL; + } else + #endif + { + *self->code_state.sp = send_value; + } } mp_obj_dict_t *old_globals = mp_globals_get(); mp_globals_set(self->globals); @@ -125,6 +134,9 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ case MP_VM_RETURN_YIELD: *ret_val = *self->code_state.sp; + #if MICROPY_PY_GENERATOR_PEND_THROW + *self->code_state.sp = mp_const_none; + #endif break; case MP_VM_RETURN_EXCEPTION: { @@ -219,10 +231,24 @@ STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_close_obj, gen_instance_close); +STATIC mp_obj_t gen_instance_pend_throw(mp_obj_t self_in, mp_obj_t exc_in) { + mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in); + if (self->code_state.sp == self->code_state.state - 1) { + mp_raise_TypeError("can't pend throw to just-started generator"); + } + mp_obj_t prev = *self->code_state.sp; + *self->code_state.sp = exc_in; + return prev; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_pend_throw_obj, gen_instance_pend_throw); + STATIC const mp_rom_map_elem_t gen_instance_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&gen_instance_close_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&gen_instance_send_obj) }, { MP_ROM_QSTR(MP_QSTR_throw), MP_ROM_PTR(&gen_instance_throw_obj) }, + #if MICROPY_PY_GENERATOR_PEND_THROW + { MP_ROM_QSTR(MP_QSTR_pend_throw), MP_ROM_PTR(&gen_instance_pend_throw_obj) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(gen_instance_locals_dict, gen_instance_locals_dict_table); diff --git a/tests/basics/generator_pend_throw.py b/tests/basics/generator_pend_throw.py new file mode 100644 index 0000000000..9496556127 --- /dev/null +++ b/tests/basics/generator_pend_throw.py @@ -0,0 +1,26 @@ +def gen(): + i = 0 + while 1: + yield i + i += 1 + +g = gen() + +try: + g.pend_throw +except AttributeError: + print("SKIP") + raise SystemExit + + +print(next(g)) +print(next(g)) +g.pend_throw(ValueError()) + +v = None +try: + v = next(g) +except Exception as e: + print("raised", repr(e)) + +print("ret was:", v) diff --git a/tests/basics/generator_pend_throw.py.exp b/tests/basics/generator_pend_throw.py.exp new file mode 100644 index 0000000000..f9894a089c --- /dev/null +++ b/tests/basics/generator_pend_throw.py.exp @@ -0,0 +1,4 @@ +0 +1 +raised ValueError() +ret was: None diff --git a/tests/run-tests b/tests/run-tests index 45cb1a7465..8719befbda 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -337,7 +337,7 @@ def run_tests(pyb, tests, args, base_path="."): # Some tests are known to fail with native emitter # Remove them from the below when they work if args.emit == 'native': - skip_tests.update({'basics/%s.py' % t for t in 'gen_yield_from gen_yield_from_close gen_yield_from_ducktype gen_yield_from_exc gen_yield_from_iter gen_yield_from_send gen_yield_from_stopped gen_yield_from_throw gen_yield_from_throw2 gen_yield_from_throw3 generator1 generator2 generator_args generator_close generator_closure generator_exc generator_return generator_send'.split()}) # require yield + skip_tests.update({'basics/%s.py' % t for t in 'gen_yield_from gen_yield_from_close gen_yield_from_ducktype gen_yield_from_exc gen_yield_from_iter gen_yield_from_send gen_yield_from_stopped gen_yield_from_throw gen_yield_from_throw2 gen_yield_from_throw3 generator1 generator2 generator_args generator_close generator_closure generator_exc generator_pend_throw generator_return generator_send'.split()}) # require yield skip_tests.update({'basics/%s.py' % t for t in 'bytes_gen class_store_class globals_del string_join'.split()}) # require yield skip_tests.update({'basics/async_%s.py' % t for t in 'def await await2 for for2 with with2'.split()}) # require yield skip_tests.update({'basics/%s.py' % t for t in 'try_reraise try_reraise2'.split()}) # require raise_varargs From 02d2a0fb3a004238b5c15e02b0699824b385ee96 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 7 Nov 2017 20:04:18 +0200 Subject: [PATCH 181/828] docs/conf: Reference CPython 3.5 docs. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CPython 3.6 contains some backward incompatible changes, and further version(s) are expected to have more. As we anyway implemente 3.4 with some features of 3.5, refer to 3.5 docs to avoid confusion. Examples of 3.6 backward incompatibilities: https://docs.python.org/3.6/library/json.html#json.dump https://docs.python.org/3.6/library/json.html#json.load > Changed in version 3.6: All optional parameters are now keyword-only. https://docs.python.org/3.6/library/functions.html#type > Changed in version 3.6: Subclasses of type which don’t override > type.__new__ may no longer use the one-argument form to get the > type of an object. https://docs.python.org/3.6/library/collections.html#collections.namedtuple > Changed in version 3.6: The verbose and rename parameters became > keyword-only arguments. --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 5352d16e45..f9c3ecdb7a 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -322,7 +322,7 @@ texinfo_documents = [ # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'python': ('http://docs.python.org/3', None)} +intersphinx_mapping = {'python': ('http://docs.python.org/3.5', None)} # Append the other ports' specific folders/files to the exclude pattern exclude_patterns.extend([port + '*' for port in ports if port != micropy_port]) From 9251f1395efff46bb63f5010534452f4c437206f Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 16 Dec 2017 10:37:36 +0200 Subject: [PATCH 182/828] docs/packages: Use "install_dir/" in examples. --- docs/reference/packages.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/reference/packages.rst b/docs/reference/packages.rst index 3d05f0b27c..efe119f719 100644 --- a/docs/reference/packages.rst +++ b/docs/reference/packages.rst @@ -130,12 +130,12 @@ transferring this image to a device by suitable means. Installing to a directory image involves using ``-p`` switch to `upip`:: - micropython -m upip install -p install_image micropython-pystone_lowmem + micropython -m upip install -p install_dir micropython-pystone_lowmem After this command, the package content (and contents of every depenency -packages) will be available in the ``install_image/`` subdirectory. You +packages) will be available in the ``install_dir/`` subdirectory. You would need to transfer contents of this directory (without the -``install_image/`` prefix) to the device, at the suitable location, where +``install_dir/`` prefix) to the device, at the suitable location, where it can be found by the Python ``import`` statement (see discussion of the `upip` installation path above). From e37ccfe59b88cbc0c1617ee1d0ec418d52ba6f76 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 16 Dec 2017 10:41:45 +0200 Subject: [PATCH 183/828] docs/packages: Explicitly recommend usage of setuptools instead of distutils. --- docs/reference/packages.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/reference/packages.rst b/docs/reference/packages.rst index efe119f719..e1609985a5 100644 --- a/docs/reference/packages.rst +++ b/docs/reference/packages.rst @@ -204,12 +204,13 @@ Creating distribution packages Distribution packages for MicroPython are created in the same manner as for CPython or any other Python implementation, see references at -the end of chapter. "Source distribution" (sdist) format is used for -packaging. The post-processing discussed above, (and pre-processing -discussed in the following section) is achieved by using custom -"sdist" command for distutils/setuptools. Thus, packaging steps -remain the same as for standard distutils/setuptools, the user just -need to override "sdist" command implementation by passing the +the end of chapter. Setuptools (instead of distutils) should be used, +because distutils do not support dependencies and other features. "Source +distribution" (``sdist``) format is used for packaging. The post-processing +discussed above, (and pre-processing discussed in the following section) +is achieved by using custom ``sdist`` command for setuptools. Thus, packaging +steps remain the same as for the standard setuptools, the user just +needs to override ``sdist`` command implementation by passing the appropriate argument to ``setup()`` call:: from setuptools import setup From 7f9a62408de96f8d78926690968ac1f9ead19f3c Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 16 Dec 2017 20:21:09 +0200 Subject: [PATCH 184/828] unix/Makefile: coverage: Allow user to pass CFLAGS_EXTRA. This build sets CFLAGS_EXTRA itself, but preserve user's value as passed on make command line/etc. --- ports/unix/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/unix/Makefile b/ports/unix/Makefile index b96391f693..b5f9f8e7da 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -243,7 +243,7 @@ freedos: # build an interpreter for coverage testing and do the testing coverage: $(MAKE) \ - COPT="-O0" CFLAGS_EXTRA='-DMP_CONFIGFILE="" \ + COPT="-O0" CFLAGS_EXTRA='$(CFLAGS_EXTRA) -DMP_CONFIGFILE="" \ -fprofile-arcs -ftest-coverage \ -Wdouble-promotion -Wformat -Wmissing-declarations -Wmissing-prototypes -Wsign-compare \ -Wold-style-definition -Wpointer-arith -Wshadow -Wuninitialized -Wunused-parameter \ From ea742085ed0ca3ce3b8b14b69442fd13ccc2a754 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 16 Dec 2017 20:43:04 +0200 Subject: [PATCH 185/828] unix/mpconfigport.h: Allow to override stackless options from commandline. --- ports/unix/mpconfigport.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index 06ae1e2343..353bfa3e4b 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -106,8 +106,10 @@ #define MICROPY_PY_GC_COLLECT_RETVAL (1) #define MICROPY_MODULE_FROZEN_STR (1) +#ifndef MICROPY_STACKLESS #define MICROPY_STACKLESS (0) #define MICROPY_STACKLESS_STRICT (0) +#endif #define MICROPY_PY_OS_STATVFS (1) #define MICROPY_PY_UTIME (1) From 5455bf79c568fa56b2ad05d28d10575d987030b4 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 16 Dec 2017 20:43:30 +0200 Subject: [PATCH 186/828] .travis.yml: Build and test strict stackless build. Previously, testing of stackless build happened (manually) in travis-stackless branch. However, stackless offers important featureset, so it's worth to test it as a part of the main CI. Strict stackless is used because it's the "real" stackless build, which avoids using C stack as much as possible (non-strict just prefers heap over C stack, but may end up using the latter). --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 4a9d238ab9..b98ee99710 100644 --- a/.travis.yml +++ b/.travis.yml @@ -61,6 +61,11 @@ script: # run coveralls coverage analysis (try to, even if some builds/tests failed) - (cd ports/unix && coveralls --root ../.. --build-root . --gcov $(which gcov) --gcov-options '\-o build-coverage/' --include py --include extmod) + # run tests on stackless build + - rm -rf ports/unix/build-coverage + - make -C ports/unix coverage CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1" + - (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests) + after_failure: - (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done) - (grep "FAIL" ports/qemu-arm/build/console.out) From 9123c8d9460017b8c8dc4a38d9a26968eacaa4cb Mon Sep 17 00:00:00 2001 From: Eric Poulsen Date: Tue, 28 Nov 2017 18:48:30 -0800 Subject: [PATCH 187/828] esp32/machine_hw_spi: Fix large HW SPI transfers by splitting them up. Breaks up HW SPI transfers into maximum chunks of 32736 bits (4092 bytes), because this is the maximum that the underlying ESP IDF will accept. --- ports/esp32/machine_hw_spi.c | 54 ++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c index 437b620f5e..54790bf8d9 100644 --- a/ports/esp32/machine_hw_spi.c +++ b/ports/esp32/machine_hw_spi.c @@ -36,6 +36,9 @@ #include "driver/spi_master.h" +#define MP_HW_SPI_MAX_XFER_BYTES (4092) +#define MP_HW_SPI_MAX_XFER_BITS (MP_HW_SPI_MAX_XFER_BYTES * 8) // Has to be an even multiple of 8 + typedef struct _machine_hw_spi_obj_t { mp_obj_base_t base; spi_host_device_t host; @@ -227,35 +230,52 @@ STATIC void machine_hw_spi_deinit(mp_obj_base_t *self_in) { STATIC void machine_hw_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { machine_hw_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); - int bits_to_send = len * self->bits; - bool shortMsg = len <= 4; - if (self->state == MACHINE_HW_SPI_STATE_DEINIT) { mp_raise_msg(&mp_type_OSError, "transfer on deinitialized SPI"); return; } - struct spi_transaction_t transaction = { - .flags = 0, - .length = bits_to_send, - .tx_buffer = NULL, - .rx_buffer = NULL, - }; + struct spi_transaction_t transaction = { 0 }; - if (shortMsg) { + // Round to nearest whole set of bits + int bits_to_send = len * 8 / self->bits * self->bits; + + + if (len <= 4) { if (src != NULL) { memcpy(&transaction.tx_data, src, len); } - transaction.flags |= (SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA); + + transaction.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA; + transaction.length = bits_to_send; + spi_device_transmit(self->spi, &transaction); + + if (dest != NULL) { + memcpy(dest, &transaction.rx_data, len); + } } else { - transaction.tx_buffer = src; - transaction.rx_buffer = dest; - } + int offset = 0; + int bits_remaining = bits_to_send; - spi_device_transmit(self->spi, &transaction); + while (bits_remaining) { + memset(&transaction, 0, sizeof(transaction)); - if (shortMsg && dest != NULL) { - memcpy(dest, &transaction.rx_data, len); + transaction.length = + bits_remaining > MP_HW_SPI_MAX_XFER_BITS ? MP_HW_SPI_MAX_XFER_BITS : bits_remaining; + + if (src != NULL) { + transaction.tx_buffer = src + offset; + } + if (dest != NULL) { + transaction.rx_buffer = dest + offset; + } + + spi_device_transmit(self->spi, &transaction); + bits_remaining -= transaction.length; + + // doesn't need ceil(); loop ends when bits_remaining is 0 + offset += transaction.length / 8; + } } } From d1fd889ad072afb1e7ffe4c0e5f4ef258226d70f Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 18 Dec 2017 15:46:08 +1100 Subject: [PATCH 188/828] esp32/machine_hw_spi: Remove unnecessary white space for consistency. --- ports/esp32/machine_hw_spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c index 54790bf8d9..d011ce53e3 100644 --- a/ports/esp32/machine_hw_spi.c +++ b/ports/esp32/machine_hw_spi.c @@ -295,7 +295,7 @@ STATIC void machine_hw_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_ enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_id, MP_ARG_INT , {.u_int = -1} }, + { MP_QSTR_id, MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, @@ -343,7 +343,7 @@ STATIC void machine_hw_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_ mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT , {.u_int = -1} }, + { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 500000} }, { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, From f5fb68e94fe72a7d8c158a47c2374ee0cea0227c Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Dec 2017 13:13:21 +1100 Subject: [PATCH 189/828] py/runtime: Remove unnecessary break statements from switch. --- py/runtime.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/py/runtime.c b/py/runtime.c index 41f2f6976e..9dff9847a0 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -413,7 +413,6 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { // use standard precision return MP_OBJ_NEW_SMALL_INT(lhs_val * rhs_val); } - break; } case MP_BINARY_OP_FLOOR_DIVIDE: case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: @@ -488,10 +487,10 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { return MP_OBJ_FROM_PTR(tuple); } - case MP_BINARY_OP_LESS: return mp_obj_new_bool(lhs_val < rhs_val); break; - case MP_BINARY_OP_MORE: return mp_obj_new_bool(lhs_val > rhs_val); break; - case MP_BINARY_OP_LESS_EQUAL: return mp_obj_new_bool(lhs_val <= rhs_val); break; - case MP_BINARY_OP_MORE_EQUAL: return mp_obj_new_bool(lhs_val >= rhs_val); break; + case MP_BINARY_OP_LESS: return mp_obj_new_bool(lhs_val < rhs_val); + case MP_BINARY_OP_MORE: return mp_obj_new_bool(lhs_val > rhs_val); + case MP_BINARY_OP_LESS_EQUAL: return mp_obj_new_bool(lhs_val <= rhs_val); + case MP_BINARY_OP_MORE_EQUAL: return mp_obj_new_bool(lhs_val >= rhs_val); default: goto unsupported_op; From 136cb7f27c27ee128d3adab9850b74f6129c8732 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Dec 2017 13:37:15 +1100 Subject: [PATCH 190/828] py/map: Don't include ordered-dict mutating code when not needed. --- py/map.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/py/map.c b/py/map.c index 696c7a2ea2..6abf4853f1 100644 --- a/py/map.c +++ b/py/map.c @@ -170,6 +170,7 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t if (map->is_ordered) { for (mp_map_elem_t *elem = &map->table[0], *top = &map->table[map->used]; elem < top; elem++) { if (elem->key == index || (!compare_only_ptrs && mp_obj_equal(elem->key, index))) { + #if MICROPY_PY_COLLECTIONS_ORDEREDDICT if (MP_UNLIKELY(lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND)) { // remove the found element by moving the rest of the array down mp_obj_t value = elem->value; @@ -180,9 +181,11 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t elem->key = MP_OBJ_NULL; elem->value = value; } + #endif return elem; } } + #if MICROPY_PY_COLLECTIONS_ORDEREDDICT if (MP_LIKELY(lookup_kind != MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)) { return NULL; } @@ -198,6 +201,9 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t map->all_keys_are_qstrs = 0; } return elem; + #else + return NULL; + #endif } // map is a hash table (not an ordered array), so do a hash lookup From 7208cad97afb4f65902f7943ace425f652eeb669 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Dec 2017 13:59:54 +1100 Subject: [PATCH 191/828] tests/basics: Add more set tests to improve coverage of py/objset.c. --- tests/basics/set_binop.py | 6 ++++++ tests/basics/set_isfooset.py | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/basics/set_binop.py b/tests/basics/set_binop.py index bc76533b1f..bf55f87db5 100644 --- a/tests/basics/set_binop.py +++ b/tests/basics/set_binop.py @@ -60,6 +60,12 @@ except TypeError: print('TypeError') # unsupported operator +try: + set('abc') * set('abc') +except TypeError: + print('TypeError') + +# unsupported operator with RHS not a set try: set('abc') * 2 except TypeError: diff --git a/tests/basics/set_isfooset.py b/tests/basics/set_isfooset.py index ce7952cd2c..27dedea00a 100644 --- a/tests/basics/set_isfooset.py +++ b/tests/basics/set_isfooset.py @@ -1,5 +1,6 @@ sets = [set(), {1}, {1, 2, 3}, {3, 4, 5}, {5, 6, 7}] +args = sets + [[1], [1, 2], [1, 2 ,3]] for i in sets: - for j in sets: + for j in args: print(i.issubset(j)) print(i.issuperset(j)) From 7db79d8b031e69392432ace687c9fcfdd2c56d4c Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Dec 2017 14:01:19 +1100 Subject: [PATCH 192/828] py/objset: Remove unneeded check from set_equal. set_equal is called only from set_binary_op, and this guarantees that the second arg to set_equal is always a set or frozenset. So there is no need to do a further check. --- py/objset.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/py/objset.c b/py/objset.c index 3e98c30e8f..799ba9df04 100644 --- a/py/objset.c +++ b/py/objset.c @@ -351,11 +351,9 @@ STATIC mp_obj_t set_issuperset_proper(mp_obj_t self_in, mp_obj_t other_in) { } STATIC mp_obj_t set_equal(mp_obj_t self_in, mp_obj_t other_in) { + assert(is_set_or_frozenset(other_in)); check_set_or_frozenset(self_in); mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); - if (!is_set_or_frozenset(other_in)) { - return mp_const_false; - } mp_obj_set_t *other = MP_OBJ_TO_PTR(other_in); if (self->set.used != other->set.used) { return mp_const_false; From 251b00457c02718373a03cd5c1aa04a67ba30711 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Dec 2017 14:45:53 +1100 Subject: [PATCH 193/828] tests/extmod/uhashlib_sha256: Add test for hashing 56 bytes of data. --- tests/extmod/uhashlib_sha256.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/extmod/uhashlib_sha256.py b/tests/extmod/uhashlib_sha256.py index 3200e8f5cd..676d479794 100644 --- a/tests/extmod/uhashlib_sha256.py +++ b/tests/extmod/uhashlib_sha256.py @@ -23,6 +23,9 @@ print(h.digest()) print(hashlib.sha256(b"\xff" * 64).digest()) +# 56 bytes is a boundary case in the algorithm +print(hashlib.sha256(b"\xff" * 56).digest()) + # TODO: running .digest() several times in row is not supported() #h = hashlib.sha256(b'123') #print(h.digest()) From 7cae17fac774bec7529581f074cfa95716b984b1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Dec 2017 14:50:33 +1100 Subject: [PATCH 194/828] tests/float/builtin_float_hash: Add test to improve objfloat.c coverage. --- tests/float/builtin_float_hash.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/float/builtin_float_hash.py b/tests/float/builtin_float_hash.py index ba6b639073..dd184595f9 100644 --- a/tests/float/builtin_float_hash.py +++ b/tests/float/builtin_float_hash.py @@ -15,6 +15,7 @@ for val in ( '0.1', '-0.1', '10.3', + '1e16', 'inf', '-inf', 'nan', From e800e4463db90b3fd971a051c12153f4d61dd10e Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Dec 2017 15:01:17 +1100 Subject: [PATCH 195/828] tests/unix: Add test for printf with %lx format. --- ports/unix/coverage.c | 1 + tests/unix/extra_coverage.py.exp | 1 + 2 files changed, 2 insertions(+) diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index e2896c2dd1..5118f90525 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -145,6 +145,7 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "%d %+d % d\n", -123, 123, 123); // sign mp_printf(&mp_plat_print, "%05d\n", -123); // negative number with zero padding mp_printf(&mp_plat_print, "%ld\n", 123); // long + mp_printf(&mp_plat_print, "%lx\n", 0x123); // long hex mp_printf(&mp_plat_print, "%X\n", 0x1abcdef); // capital hex mp_printf(&mp_plat_print, "%.2s %.3s\n", "abc", "abc"); // fixed string precision mp_printf(&mp_plat_print, "%.*s\n", -1, "abc"); // negative string precision diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index 1db46ab8f4..bbac5f3d73 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -2,6 +2,7 @@ -123 +123 123 -0123 123 +123 1ABCDEF ab abc From 8e6113a18808792c5d1eb30e54bb0a1694bb4042 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Dec 2017 15:01:49 +1100 Subject: [PATCH 196/828] tests/basics/generator_pend_throw: Add test for just-started generator. --- tests/basics/generator_pend_throw.py | 5 +++++ tests/basics/generator_pend_throw.py.exp | 1 + 2 files changed, 6 insertions(+) diff --git a/tests/basics/generator_pend_throw.py b/tests/basics/generator_pend_throw.py index 9496556127..f00ff793b6 100644 --- a/tests/basics/generator_pend_throw.py +++ b/tests/basics/generator_pend_throw.py @@ -24,3 +24,8 @@ except Exception as e: print("raised", repr(e)) print("ret was:", v) + +try: + gen().pend_throw(ValueError()) +except TypeError: + print("TypeError") diff --git a/tests/basics/generator_pend_throw.py.exp b/tests/basics/generator_pend_throw.py.exp index f9894a089c..ed4d882958 100644 --- a/tests/basics/generator_pend_throw.py.exp +++ b/tests/basics/generator_pend_throw.py.exp @@ -2,3 +2,4 @@ 1 raised ValueError() ret was: None +TypeError From 374eaf5271c9bfc63b5aa1139de55753ad67cc9a Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Dec 2017 15:42:58 +1100 Subject: [PATCH 197/828] py/mpz: Fix pow3 function so it handles the case when 3rd arg is 1. In this case the result should always be 0, even if 2nd arg is 0. --- py/mpz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/mpz.c b/py/mpz.c index d300a8e5db..16112c2012 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -1390,7 +1390,7 @@ void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { can have dest, lhs, rhs the same; mod can't be the same as dest */ void mpz_pow3_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs, const mpz_t *mod) { - if (lhs->len == 0 || rhs->neg != 0) { + if (lhs->len == 0 || rhs->neg != 0 || (mod->len == 1 && mod->dig[0] == 1)) { mpz_set_from_int(dest, 0); return; } From 2bfa531798de1061e1417785acc42b892f96f532 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Dec 2017 15:44:10 +1100 Subject: [PATCH 198/828] tests/basics/builtin_pow3: Add tests for edge cases of pow3. --- tests/basics/builtin_pow3.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/basics/builtin_pow3.py b/tests/basics/builtin_pow3.py index 69b57e5484..94e657bc44 100644 --- a/tests/basics/builtin_pow3.py +++ b/tests/basics/builtin_pow3.py @@ -7,6 +7,12 @@ except NotImplementedError: print("SKIP") raise SystemExit +# test some edge cases +print(pow(1, 1, 1)) +print(pow(0, 1, 1)) +print(pow(1, 0, 1)) +print(pow(1, 0, 2)) + # 3 arg pow is defined to only work on integers try: print(pow("x", 5, 6)) From ae1be76d4063997b2703ba1ac9d009b31bc06eca Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Dec 2017 15:45:56 +1100 Subject: [PATCH 199/828] py/mpz: Apply a small code-size optimisation. --- py/mpz.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/py/mpz.c b/py/mpz.c index 16112c2012..018a5454f8 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -1395,8 +1395,9 @@ void mpz_pow3_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs, const mpz_t return; } + mpz_set_from_int(dest, 1); + if (rhs->len == 0) { - mpz_set_from_int(dest, 1); return; } @@ -1404,8 +1405,6 @@ void mpz_pow3_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs, const mpz_t mpz_t *n = mpz_clone(rhs); mpz_t quo; mpz_init_zero(&quo); - mpz_set_from_int(dest, 1); - while (n->len > 0) { if ((n->dig[0] & 1) != 0) { mpz_mul_inpl(dest, dest, x); From 35a759dc1dae33d62d005fe44f3cda4599a3c297 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Dec 2017 16:13:00 +1100 Subject: [PATCH 200/828] tests: Add some more tests to improve coverage of py/parse.c. --- tests/basics/errno1.py | 4 ++++ tests/basics/errno1.py.exp | 1 + tests/basics/int_constfolding.py | 6 ++++++ tests/basics/syntaxerror.py | 4 ++++ tests/cmdline/cmd_parsetree.py | 1 + tests/cmdline/cmd_parsetree.py.exp | 12 +++++++++--- 6 files changed, 25 insertions(+), 3 deletions(-) diff --git a/tests/basics/errno1.py b/tests/basics/errno1.py index 63930b767f..d7a5ccd542 100644 --- a/tests/basics/errno1.py +++ b/tests/basics/errno1.py @@ -15,3 +15,7 @@ print(msg[:7], msg[-5:]) # check that unknown errno is still rendered print(str(OSError(9999))) + +# this tests a failed constant lookup in errno +errno = uerrno +print(errno.__name__) diff --git a/tests/basics/errno1.py.exp b/tests/basics/errno1.py.exp index c3703df4a2..7dd22757dd 100644 --- a/tests/basics/errno1.py.exp +++ b/tests/basics/errno1.py.exp @@ -1,3 +1,4 @@ [Errno ] EIO 9999 +uerrno diff --git a/tests/basics/int_constfolding.py b/tests/basics/int_constfolding.py index 7bb5383785..158897f553 100644 --- a/tests/basics/int_constfolding.py +++ b/tests/basics/int_constfolding.py @@ -29,3 +29,9 @@ print(123 // 7, 123 % 7) print(-123 // 7, -123 % 7) print(123 // -7, 123 % -7) print(-123 // -7, -123 % -7) + +# won't fold so an exception can be raised at runtime +try: + 1 << -1 +except ValueError: + print('ValueError') diff --git a/tests/basics/syntaxerror.py b/tests/basics/syntaxerror.py index 4161de017b..843459f0bf 100644 --- a/tests/basics/syntaxerror.py +++ b/tests/basics/syntaxerror.py @@ -29,6 +29,10 @@ test_syntax(" a\n") # malformed integer literal (parser error) test_syntax("123z") +# input doesn't match the grammar (parser error) +test_syntax('1 or 2 or') +test_syntax('{1:') + # can't assign to literals test_syntax("1 = 2") test_syntax("'' = 1") diff --git a/tests/cmdline/cmd_parsetree.py b/tests/cmdline/cmd_parsetree.py index 5f698eeae3..da36c80703 100644 --- a/tests/cmdline/cmd_parsetree.py +++ b/tests/cmdline/cmd_parsetree.py @@ -9,3 +9,4 @@ c = 'a very long str that will not be interned' d = b'bytes' e = b'a very long bytes that will not be interned' f = 123456789012345678901234567890 +g = 123 diff --git a/tests/cmdline/cmd_parsetree.py.exp b/tests/cmdline/cmd_parsetree.py.exp index d9f81d8d4c..12a1bfbe90 100644 --- a/tests/cmdline/cmd_parsetree.py.exp +++ b/tests/cmdline/cmd_parsetree.py.exp @@ -1,5 +1,5 @@ ---------------- -[ 4] rule(1) (n=8) +[ 4] rule(1) (n=9) tok(4) [ 4] rule(22) (n=4) id(i) @@ -25,6 +25,9 @@ [ 11] rule(5) (n=2) id(f) [ 11] literal \.\+ +[ 12] rule(5) (n=2) + id(g) + int(123) ---------------- File cmdline/cmd_parsetree.py, code block '' (descriptor: \.\+, bytecode @\.\+ bytes) Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): @@ -42,6 +45,7 @@ arg names: bc=27 line=9 bc=32 line=10 bc=37 line=11 + bc=42 line=12 00 BUILD_TUPLE 0 02 GET_ITER_STACK 03 FOR_ITER 12 @@ -59,8 +63,10 @@ arg names: 34 STORE_NAME e 37 LOAD_CONST_OBJ \.\+ 39 STORE_NAME f -42 LOAD_CONST_NONE -43 RETURN_VALUE +42 LOAD_CONST_SMALL_INT 123 +45 STORE_NAME g +48 LOAD_CONST_NONE +49 RETURN_VALUE mem: total=\\d\+, current=\\d\+, peak=\\d\+ stack: \\d\+ out of \\d\+ GC: total: \\d\+, used: \\d\+, free: \\d\+ From d35c6ffc84e94dca370479a057eed60b9b347c1b Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Dec 2017 16:48:41 +1100 Subject: [PATCH 201/828] tests/extmod: Add some uctypes tests to improve coverage of that module. --- tests/extmod/uctypes_bytearray.py | 3 ++ tests/extmod/uctypes_bytearray.py.exp | 1 + tests/extmod/uctypes_byteat.py | 10 +++++++ tests/extmod/uctypes_byteat.py.exp | 2 ++ tests/extmod/uctypes_error.py | 37 ++++++++++++++++++++++++ tests/extmod/uctypes_error.py.exp | 4 +++ tests/extmod/uctypes_sizeof.py | 5 ++++ tests/extmod/uctypes_sizeof.py.exp | 1 + tests/extmod/uctypes_sizeof_float.py | 8 +++++ tests/extmod/uctypes_sizeof_float.py.exp | 2 ++ 10 files changed, 73 insertions(+) create mode 100644 tests/extmod/uctypes_byteat.py create mode 100644 tests/extmod/uctypes_byteat.py.exp create mode 100644 tests/extmod/uctypes_error.py create mode 100644 tests/extmod/uctypes_error.py.exp create mode 100644 tests/extmod/uctypes_sizeof_float.py create mode 100644 tests/extmod/uctypes_sizeof_float.py.exp diff --git a/tests/extmod/uctypes_bytearray.py b/tests/extmod/uctypes_bytearray.py index 61c7da271f..77c93c3766 100644 --- a/tests/extmod/uctypes_bytearray.py +++ b/tests/extmod/uctypes_bytearray.py @@ -17,3 +17,6 @@ S = uctypes.struct(uctypes.addressof(data), desc, uctypes.LITTLE_ENDIAN) print(S.arr) # But not INT8, because value range is different print(type(S.arr2)) + +# convert to buffer +print(bytearray(S)) diff --git a/tests/extmod/uctypes_bytearray.py.exp b/tests/extmod/uctypes_bytearray.py.exp index 294f8a5fa4..7c84edbb6d 100644 --- a/tests/extmod/uctypes_bytearray.py.exp +++ b/tests/extmod/uctypes_bytearray.py.exp @@ -1,2 +1,3 @@ bytearray(b'01') +bytearray(b'0123') diff --git a/tests/extmod/uctypes_byteat.py b/tests/extmod/uctypes_byteat.py new file mode 100644 index 0000000000..ab2535db8f --- /dev/null +++ b/tests/extmod/uctypes_byteat.py @@ -0,0 +1,10 @@ +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +data = bytearray(b'01234567') + +print(uctypes.bytes_at(uctypes.addressof(data), 4)) +print(uctypes.bytearray_at(uctypes.addressof(data), 4)) diff --git a/tests/extmod/uctypes_byteat.py.exp b/tests/extmod/uctypes_byteat.py.exp new file mode 100644 index 0000000000..e1ae4d0534 --- /dev/null +++ b/tests/extmod/uctypes_byteat.py.exp @@ -0,0 +1,2 @@ +b'0123' +bytearray(b'0123') diff --git a/tests/extmod/uctypes_error.py b/tests/extmod/uctypes_error.py new file mode 100644 index 0000000000..95ba0fad44 --- /dev/null +++ b/tests/extmod/uctypes_error.py @@ -0,0 +1,37 @@ +# test general errors with uctypes + +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +data = bytearray(b"01234567") + +# del subscr not supported +S = uctypes.struct(uctypes.addressof(data), {}) +try: + del S[0] +except TypeError: + print('TypeError') + +# list is an invalid descriptor +S = uctypes.struct(uctypes.addressof(data), []) +try: + S.x +except TypeError: + print('TypeError') + +# can't access attribute with invalid descriptor +S = uctypes.struct(uctypes.addressof(data), {'x':[]}) +try: + S.x +except TypeError: + print('TypeError') + +# can't assign to aggregate +S = uctypes.struct(uctypes.addressof(data), {'x':(uctypes.ARRAY | 0, uctypes.INT8 | 2)}) +try: + S.x = 1 +except TypeError: + print('TypeError') diff --git a/tests/extmod/uctypes_error.py.exp b/tests/extmod/uctypes_error.py.exp new file mode 100644 index 0000000000..802c260d2b --- /dev/null +++ b/tests/extmod/uctypes_error.py.exp @@ -0,0 +1,4 @@ +TypeError +TypeError +TypeError +TypeError diff --git a/tests/extmod/uctypes_sizeof.py b/tests/extmod/uctypes_sizeof.py index 5a6adb4376..e42e06c924 100644 --- a/tests/extmod/uctypes_sizeof.py +++ b/tests/extmod/uctypes_sizeof.py @@ -40,3 +40,8 @@ assert uctypes.sizeof(S.arr4) == 6 print(uctypes.sizeof(S.sub)) assert uctypes.sizeof(S.sub) == 1 +# invalid descriptor +try: + print(uctypes.sizeof([])) +except TypeError: + print("TypeError") diff --git a/tests/extmod/uctypes_sizeof.py.exp b/tests/extmod/uctypes_sizeof.py.exp index fb74def602..b35b11aa0c 100644 --- a/tests/extmod/uctypes_sizeof.py.exp +++ b/tests/extmod/uctypes_sizeof.py.exp @@ -4,3 +4,4 @@ TypeError 6 1 +TypeError diff --git a/tests/extmod/uctypes_sizeof_float.py b/tests/extmod/uctypes_sizeof_float.py new file mode 100644 index 0000000000..1ba8871bdc --- /dev/null +++ b/tests/extmod/uctypes_sizeof_float.py @@ -0,0 +1,8 @@ +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +print(uctypes.sizeof({'f':uctypes.FLOAT32})) +print(uctypes.sizeof({'f':uctypes.FLOAT64})) diff --git a/tests/extmod/uctypes_sizeof_float.py.exp b/tests/extmod/uctypes_sizeof_float.py.exp new file mode 100644 index 0000000000..de78180725 --- /dev/null +++ b/tests/extmod/uctypes_sizeof_float.py.exp @@ -0,0 +1,2 @@ +4 +8 From 304a3bcc1cf4f272b62a6cd8f14583db84d84189 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Dec 2017 16:59:08 +1100 Subject: [PATCH 202/828] py/modio: Use correct config macro to enable resource_stream function. --- py/modio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/py/modio.c b/py/modio.c index 828bcec464..3a5c69c4c1 100644 --- a/py/modio.c +++ b/py/modio.c @@ -131,7 +131,7 @@ STATIC const mp_obj_type_t bufwriter_type = { }; #endif // MICROPY_PY_IO_BUFFEREDWRITER -#if MICROPY_MODULE_FROZEN_STR +#if MICROPY_PY_IO_RESOURCE_STREAM STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) { VSTR_FIXED(path_buf, MICROPY_ALLOC_PATH_MAX); size_t len; @@ -179,7 +179,7 @@ STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) { mp_obj_t path_out = mp_obj_new_str(path_buf.buf, path_buf.len); return mp_builtin_open(1, &path_out, (mp_map_t*)&mp_const_empty_map); } -MP_DEFINE_CONST_FUN_OBJ_2(resource_stream_obj, resource_stream); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(resource_stream_obj, resource_stream); #endif STATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = { From d8d633f15658911369d7b1b912777fa74efd3ea6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Dec 2017 17:04:55 +1100 Subject: [PATCH 203/828] unix/mpconfigport_coverage.h: Enable MICROPY_PY_IO_RESOURCE_STREAM. Where possible it's important to test all code in the code base. --- ports/unix/mpconfigport_coverage.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/unix/mpconfigport_coverage.h b/ports/unix/mpconfigport_coverage.h index 0dcfdd5fd8..cf976bf7a3 100644 --- a/ports/unix/mpconfigport_coverage.h +++ b/ports/unix/mpconfigport_coverage.h @@ -41,6 +41,7 @@ #define MICROPY_PY_SYS_GETSIZEOF (1) #define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) #define MICROPY_PY_IO_BUFFEREDWRITER (1) +#define MICROPY_PY_IO_RESOURCE_STREAM (1) #undef MICROPY_VFS_FAT #define MICROPY_VFS_FAT (1) #define MICROPY_PY_FRAMEBUF (1) From 6a3a742a6c9caaa2be0fd0aac7a5df4ac816081c Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 18 Dec 2017 18:57:15 +1100 Subject: [PATCH 204/828] py/nlr: Factor out common NLR code to generic functions. Each NLR implementation (Thumb, x86, x64, xtensa, setjmp) duplicates a lot of the NLR code, specifically that dealing with pushing and popping the NLR pointer to maintain the linked-list of NLR buffers. This patch factors all of that code out of the specific implementations into generic functions in nlr.c. This eliminates duplicated code. The factoring also allows to make the machine-specific NLR code pure assembler code, thus allowing nlrthumb.c to use naked function attributes in the correct way (naked functions can only have basic inline assembler code in them). There is a small overhead introduced (typically 1 machine instruction) because now the generic nlr_jump() must call nlr_jump_tail() rather than them being one combined function. --- py/nlr.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++ py/nlr.h | 71 +++++++++++++++++++++++------------------------- py/nlrsetjmp.c | 10 +------ py/nlrthumb.c | 38 ++------------------------ py/nlrx64.c | 70 ++++++++++++++++++----------------------------- py/nlrx86.c | 63 +++++++++--------------------------------- py/nlrxtensa.c | 34 ++++------------------- py/py.mk | 1 + 8 files changed, 157 insertions(+), 204 deletions(-) create mode 100644 py/nlr.c diff --git a/py/nlr.c b/py/nlr.c new file mode 100644 index 0000000000..e4d6d10c0b --- /dev/null +++ b/py/nlr.c @@ -0,0 +1,74 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpstate.h" + +// Helper macros to save/restore the pystack state +#if MICROPY_ENABLE_PYSTACK +#define MP_NLR_SAVE_PYSTACK(nlr_buf) (nlr_buf)->pystack = MP_STATE_THREAD(pystack_cur) +#define MP_NLR_RESTORE_PYSTACK(nlr_buf) MP_STATE_THREAD(pystack_cur) = (nlr_buf)->pystack +#else +#define MP_NLR_SAVE_PYSTACK(nlr_buf) (void)nlr_buf +#define MP_NLR_RESTORE_PYSTACK(nlr_buf) (void)nlr_buf +#endif + +#if !MICROPY_NLR_SETJMP +// When not using setjmp, nlr_push_tail is called from inline asm so needs special care +#if MICROPY_NLR_X86 && (defined(_WIN32) || defined(__CYGWIN__)) +// On these 32-bit platforms make sure nlr_push_tail doesn't have a leading underscore +unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail"); +#else +// LTO can't see inside inline asm functions so explicitly mark nlr_push_tail as used +__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); +#endif +#endif + +unsigned int nlr_push_tail(nlr_buf_t *nlr) { + nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); + nlr->prev = *top; + MP_NLR_SAVE_PYSTACK(nlr); + *top = nlr; + return 0; // normal return +} + +void nlr_pop(void) { + nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); + *top = (*top)->prev; +} + +NORETURN void nlr_jump(void *val) { + nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); + nlr_buf_t *top = *top_ptr; + if (top == NULL) { + nlr_jump_fail(val); + } + + top->ret_val = val; + MP_NLR_RESTORE_PYSTACK(top); + *top_ptr = top->prev; + + nlr_jump_tail(top); +} diff --git a/py/nlr.h b/py/nlr.h index 1235f14609..012a73c311 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -30,29 +30,29 @@ // exception handling, basically a stack of setjmp/longjmp buffers #include -#include #include #include "py/mpconfig.h" -typedef struct _nlr_buf_t nlr_buf_t; -struct _nlr_buf_t { - // the entries here must all be machine word size - nlr_buf_t *prev; - void *ret_val; // always a concrete object (an exception instance) -#if !defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP +// If MICROPY_NLR_SETJMP is not enabled then auto-detect the machine arch +// Allow a port to set MICROPY_NLR_NUM_REGS to define their own implementation +#if !MICROPY_NLR_SETJMP && !defined(MICROPY_NLR_NUM_REGS) #if defined(__i386__) - void *regs[6]; + #define MICROPY_NLR_X86 (1) + #define MICROPY_NLR_NUM_REGS (6) #elif defined(__x86_64__) - #if defined(__CYGWIN__) - void *regs[12]; - #else - void *regs[8]; - #endif + #define MICROPY_NLR_X64 (1) + #if defined(__CYGWIN__) + #define MICROPY_NLR_NUM_REGS (12) + #else + #define MICROPY_NLR_NUM_REGS (8) + #endif #elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__) - void *regs[10]; + #define MICROPY_NLR_THUMB (1) + #define MICROPY_NLR_NUM_REGS (10) #elif defined(__xtensa__) - void *regs[10]; + #define MICROPY_NLR_XTENSA (1) + #define MICROPY_NLR_NUM_REGS (10) #else #define MICROPY_NLR_SETJMP (1) //#warning "No native NLR support for this arch, using setjmp implementation" @@ -60,41 +60,39 @@ struct _nlr_buf_t { #endif #if MICROPY_NLR_SETJMP - jmp_buf jmpbuf; +#include #endif +typedef struct _nlr_buf_t nlr_buf_t; +struct _nlr_buf_t { + // the entries here must all be machine word size + nlr_buf_t *prev; + void *ret_val; // always a concrete object (an exception instance) + + #if MICROPY_NLR_SETJMP + jmp_buf jmpbuf; + #else + void *regs[MICROPY_NLR_NUM_REGS]; + #endif + #if MICROPY_ENABLE_PYSTACK void *pystack; #endif }; -// Helper macros to save/restore the pystack state -#if MICROPY_ENABLE_PYSTACK -#define MP_NLR_SAVE_PYSTACK(nlr_buf) (nlr_buf)->pystack = MP_STATE_THREAD(pystack_cur) -#define MP_NLR_RESTORE_PYSTACK(nlr_buf) MP_STATE_THREAD(pystack_cur) = (nlr_buf)->pystack -#else -#define MP_NLR_SAVE_PYSTACK(nlr_buf) (void)nlr_buf -#define MP_NLR_RESTORE_PYSTACK(nlr_buf) (void)nlr_buf -#endif - #if MICROPY_NLR_SETJMP -#include "py/mpstate.h" - -NORETURN void nlr_setjmp_jump(void *val); // nlr_push() must be defined as a macro, because "The stack context will be // invalidated if the function which called setjmp() returns." -#define nlr_push(buf) ( \ - (buf)->prev = MP_STATE_THREAD(nlr_top), \ - MP_NLR_SAVE_PYSTACK(buf), \ - MP_STATE_THREAD(nlr_top) = (buf), \ - setjmp((buf)->jmpbuf)) -#define nlr_pop() { MP_STATE_THREAD(nlr_top) = MP_STATE_THREAD(nlr_top)->prev; } -#define nlr_jump(val) nlr_setjmp_jump(val) +// For this case it is safe to call nlr_push_tail() first. +#define nlr_push(buf) (nlr_push_tail(buf), setjmp((buf)->jmpbuf)) #else unsigned int nlr_push(nlr_buf_t *); +#endif + +unsigned int nlr_push_tail(nlr_buf_t *top); void nlr_pop(void); NORETURN void nlr_jump(void *val); -#endif +NORETURN void nlr_jump_tail(nlr_buf_t *top); // This must be implemented by a port. It's called by nlr_jump // if no nlr buf has been pushed. It must not return, but rather @@ -123,7 +121,6 @@ NORETURN void nlr_jump_fail(void *val); /* #define nlr_push(val) \ printf("nlr_push: before: nlr_top=%p, val=%p\n", MP_STATE_THREAD(nlr_top), val),assert(MP_STATE_THREAD(nlr_top) != val),nlr_push(val) -#endif */ #endif diff --git a/py/nlrsetjmp.c b/py/nlrsetjmp.c index 63376a5537..6ddad37934 100644 --- a/py/nlrsetjmp.c +++ b/py/nlrsetjmp.c @@ -28,15 +28,7 @@ #if MICROPY_NLR_SETJMP -void nlr_setjmp_jump(void *val) { - nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); - nlr_buf_t *top = *top_ptr; - if (top == NULL) { - nlr_jump_fail(val); - } - top->ret_val = val; - MP_NLR_RESTORE_PYSTACK(top); - *top_ptr = top->prev; +NORETURN void nlr_jump_tail(nlr_buf_t *top) { longjmp(top->jmpbuf, 1); } diff --git a/py/nlrthumb.c b/py/nlrthumb.c index eab5759f21..4edd1456dd 100644 --- a/py/nlrthumb.c +++ b/py/nlrthumb.c @@ -26,7 +26,7 @@ #include "py/mpstate.h" -#if (!defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP) && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) +#if MICROPY_NLR_THUMB #undef nlr_push @@ -37,7 +37,6 @@ // r4-r11, r13=sp __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { - __asm volatile ( "str r4, [r0, #12] \n" // store r4 into nlr_buf "str r5, [r0, #16] \n" // store r5 into nlr_buf @@ -75,36 +74,10 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { "b nlr_push_tail \n" // do the rest in C #endif ); - - return 0; // needed to silence compiler warning } -__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - nlr->prev = *top; - MP_NLR_SAVE_PYSTACK(nlr); - *top = nlr; - return 0; // normal return -} - -void nlr_pop(void) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - *top = (*top)->prev; -} - -NORETURN __attribute__((naked)) void nlr_jump(void *val) { - nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); - nlr_buf_t *top = *top_ptr; - if (top == NULL) { - nlr_jump_fail(val); - } - - top->ret_val = val; - MP_NLR_RESTORE_PYSTACK(top); - *top_ptr = top->prev; - +NORETURN __attribute__((naked)) void nlr_jump_tail(nlr_buf_t *top) { __asm volatile ( - "mov r0, %0 \n" // r0 points to nlr_buf "ldr r4, [r0, #12] \n" // load r4 from nlr_buf "ldr r5, [r0, #16] \n" // load r5 from nlr_buf "ldr r6, [r0, #20] \n" // load r6 from nlr_buf @@ -133,12 +106,7 @@ NORETURN __attribute__((naked)) void nlr_jump(void *val) { #endif "movs r0, #1 \n" // return 1, non-local return "bx lr \n" // return - : // output operands - : "r"(top) // input operands - : // clobbered registers ); - - for (;;); // needed to silence compiler warning } -#endif // (!defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP) && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) +#endif // MICROPY_NLR_THUMB diff --git a/py/nlrx64.c b/py/nlrx64.c index ddcd761665..e7e2e14748 100644 --- a/py/nlrx64.c +++ b/py/nlrx64.c @@ -26,7 +26,7 @@ #include "py/mpstate.h" -#if !MICROPY_NLR_SETJMP && defined(__x86_64__) +#if MICROPY_NLR_X64 #undef nlr_push @@ -39,8 +39,6 @@ #define NLR_OS_WINDOWS 0 #endif -__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); - unsigned int nlr_push(nlr_buf_t *nlr) { (void)nlr; @@ -88,54 +86,38 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; // needed to silence compiler warning } -__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - nlr->prev = *top; - MP_NLR_SAVE_PYSTACK(nlr); - *top = nlr; - return 0; // normal return -} - -void nlr_pop(void) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - *top = (*top)->prev; -} - -NORETURN void nlr_jump(void *val) { - nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); - nlr_buf_t *top = *top_ptr; - if (top == NULL) { - nlr_jump_fail(val); - } - - top->ret_val = val; - MP_NLR_RESTORE_PYSTACK(top); - *top_ptr = top->prev; +NORETURN void nlr_jump_tail(nlr_buf_t *top) { + (void)top; __asm volatile ( - "movq %0, %%rcx \n" // %rcx points to nlr_buf #if NLR_OS_WINDOWS - "movq 88(%%rcx), %%rsi \n" // load saved %rsi - "movq 80(%%rcx), %%rdi \n" // load saved %rdr + "movq 88(%rcx), %rsi \n" // load saved %rsi + "movq 80(%rcx), %rdi \n" // load saved %rdr + "movq 72(%rcx), %r15 \n" // load saved %r15 + "movq 64(%rcx), %r14 \n" // load saved %r14 + "movq 56(%rcx), %r13 \n" // load saved %r13 + "movq 48(%rcx), %r12 \n" // load saved %r12 + "movq 40(%rcx), %rbx \n" // load saved %rbx + "movq 32(%rcx), %rsp \n" // load saved %rsp + "movq 24(%rcx), %rbp \n" // load saved %rbp + "movq 16(%rcx), %rax \n" // load saved %rip + #else + "movq 72(%rdi), %r15 \n" // load saved %r15 + "movq 64(%rdi), %r14 \n" // load saved %r14 + "movq 56(%rdi), %r13 \n" // load saved %r13 + "movq 48(%rdi), %r12 \n" // load saved %r12 + "movq 40(%rdi), %rbx \n" // load saved %rbx + "movq 32(%rdi), %rsp \n" // load saved %rsp + "movq 24(%rdi), %rbp \n" // load saved %rbp + "movq 16(%rdi), %rax \n" // load saved %rip #endif - "movq 72(%%rcx), %%r15 \n" // load saved %r15 - "movq 64(%%rcx), %%r14 \n" // load saved %r14 - "movq 56(%%rcx), %%r13 \n" // load saved %r13 - "movq 48(%%rcx), %%r12 \n" // load saved %r12 - "movq 40(%%rcx), %%rbx \n" // load saved %rbx - "movq 32(%%rcx), %%rsp \n" // load saved %rsp - "movq 24(%%rcx), %%rbp \n" // load saved %rbp - "movq 16(%%rcx), %%rax \n" // load saved %rip - "movq %%rax, (%%rsp) \n" // store saved %rip to stack - "xorq %%rax, %%rax \n" // clear return register - "inc %%al \n" // increase to make 1, non-local return + "movq %rax, (%rsp) \n" // store saved %rip to stack + "xorq %rax, %rax \n" // clear return register + "inc %al \n" // increase to make 1, non-local return "ret \n" // return - : // output operands - : "r"(top) // input operands - : // clobbered registers ); for (;;); // needed to silence compiler warning } -#endif // !MICROPY_NLR_SETJMP && defined(__x86_64__) +#endif // MICROPY_NLR_X64 diff --git a/py/nlrx86.c b/py/nlrx86.c index 3a27460eb6..cc37f72afb 100644 --- a/py/nlrx86.c +++ b/py/nlrx86.c @@ -26,25 +26,13 @@ #include "py/mpstate.h" -#if !MICROPY_NLR_SETJMP && defined(__i386__) +#if MICROPY_NLR_X86 #undef nlr_push // For reference, x86 callee save regs are: // ebx, esi, edi, ebp, esp, eip -#if defined(_WIN32) || defined(__CYGWIN__) -#define NLR_OS_WINDOWS 1 -#else -#define NLR_OS_WINDOWS 0 -#endif - -#if NLR_OS_WINDOWS -unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail"); -#else -__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); -#endif - unsigned int nlr_push(nlr_buf_t *nlr) { (void)nlr; @@ -70,48 +58,23 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; // needed to silence compiler warning } -__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - nlr->prev = *top; - MP_NLR_SAVE_PYSTACK(nlr); - *top = nlr; - return 0; // normal return -} - -void nlr_pop(void) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - *top = (*top)->prev; -} - -NORETURN void nlr_jump(void *val) { - nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); - nlr_buf_t *top = *top_ptr; - if (top == NULL) { - nlr_jump_fail(val); - } - - top->ret_val = val; - MP_NLR_RESTORE_PYSTACK(top); - *top_ptr = top->prev; +NORETURN void nlr_jump_tail(nlr_buf_t *top) { + (void)top; __asm volatile ( - "mov %0, %%edx \n" // %edx points to nlr_buf - "mov 28(%%edx), %%esi \n" // load saved %esi - "mov 24(%%edx), %%edi \n" // load saved %edi - "mov 20(%%edx), %%ebx \n" // load saved %ebx - "mov 16(%%edx), %%esp \n" // load saved %esp - "mov 12(%%edx), %%ebp \n" // load saved %ebp - "mov 8(%%edx), %%eax \n" // load saved %eip - "mov %%eax, (%%esp) \n" // store saved %eip to stack - "xor %%eax, %%eax \n" // clear return register - "inc %%al \n" // increase to make 1, non-local return + "mov 28(%edx), %esi \n" // load saved %esi + "mov 24(%edx), %edi \n" // load saved %edi + "mov 20(%edx), %ebx \n" // load saved %ebx + "mov 16(%edx), %esp \n" // load saved %esp + "mov 12(%edx), %ebp \n" // load saved %ebp + "mov 8(%edx), %eax \n" // load saved %eip + "mov %eax, (%esp) \n" // store saved %eip to stack + "xor %eax, %eax \n" // clear return register + "inc %al \n" // increase to make 1, non-local return "ret \n" // return - : // output operands - : "r"(top) // input operands - : // clobbered registers ); for (;;); // needed to silence compiler warning } -#endif // !MICROPY_NLR_SETJMP && defined(__i386__) +#endif // MICROPY_NLR_X86 diff --git a/py/nlrxtensa.c b/py/nlrxtensa.c index 5a969fc87c..6b99182271 100644 --- a/py/nlrxtensa.c +++ b/py/nlrxtensa.c @@ -26,7 +26,7 @@ #include "py/mpstate.h" -#if !MICROPY_NLR_SETJMP && defined(__xtensa__) +#if MICROPY_NLR_XTENSA #undef nlr_push @@ -37,6 +37,7 @@ // a3-a7 = rest of args unsigned int nlr_push(nlr_buf_t *nlr) { + (void)nlr; __asm volatile ( "s32i.n a0, a2, 8 \n" // save regs... @@ -55,32 +56,10 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; // needed to silence compiler warning } -__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - nlr->prev = *top; - MP_NLR_SAVE_PYSTACK(nlr); - *top = nlr; - return 0; // normal return -} - -void nlr_pop(void) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - *top = (*top)->prev; -} - -NORETURN void nlr_jump(void *val) { - nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); - nlr_buf_t *top = *top_ptr; - if (top == NULL) { - nlr_jump_fail(val); - } - - top->ret_val = val; - MP_NLR_RESTORE_PYSTACK(top); - *top_ptr = top->prev; +NORETURN void nlr_jump_tail(nlr_buf_t *top) { + (void)top; __asm volatile ( - "mov.n a2, %0 \n" // a2 points to nlr_buf "l32i.n a0, a2, 8 \n" // restore regs... "l32i.n a1, a2, 12 \n" "l32i.n a8, a2, 16 \n" @@ -93,12 +72,9 @@ NORETURN void nlr_jump(void *val) { "l32i.n a15, a2, 44 \n" "movi.n a2, 1 \n" // return 1, non-local return "ret.n \n" // return - : // output operands - : "r"(top) // input operands - : // clobbered registers ); for (;;); // needed to silence compiler warning } -#endif // !MICROPY_NLR_SETJMP && defined(__xtensa__) +#endif // MICROPY_NLR_XTENSA diff --git a/py/py.mk b/py/py.mk index 0b5d5f8c40..de82a971bc 100644 --- a/py/py.mk +++ b/py/py.mk @@ -103,6 +103,7 @@ endif # py object files PY_O_BASENAME = \ mpstate.o \ + nlr.o \ nlrx86.o \ nlrx64.o \ nlrthumb.o \ From d7a52e15398e1746d0b2fd651d11d092fa59c580 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Dec 2017 11:15:41 +1100 Subject: [PATCH 205/828] qemu-arm/test_main: Include setjmp.h because it's used by gc_collect. And it's no longer unconditionally included by nlr.h, only if NLR_SETJMP is defined. --- ports/qemu-arm/test_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/qemu-arm/test_main.c b/ports/qemu-arm/test_main.c index 926478ea1b..adbdf04e18 100644 --- a/ports/qemu-arm/test_main.c +++ b/ports/qemu-arm/test_main.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "py/obj.h" #include "py/compile.h" From 26d4a6fa45526fa7c267cd9228259642701708f6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 20 Dec 2017 16:54:31 +1100 Subject: [PATCH 206/828] py/malloc: Remove unneeded code checking m_malloc return value. m_malloc already checks for a failed allocation so there's no need to check for it in m_malloc0. --- py/malloc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/py/malloc.c b/py/malloc.c index 6835ed7c99..ba5c952f3a 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -117,9 +117,6 @@ void *m_malloc_with_finaliser(size_t num_bytes) { void *m_malloc0(size_t num_bytes) { void *ptr = m_malloc(num_bytes); - if (ptr == NULL && num_bytes != 0) { - m_malloc_fail(num_bytes); - } // If this config is set then the GC clears all memory, so we don't need to. #if !MICROPY_GC_CONSERVATIVE_CLEAR memset(ptr, 0, num_bytes); From a1d85d6199c03871ccf16700743160fad64d057b Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 20 Dec 2017 16:58:27 +1100 Subject: [PATCH 207/828] tests/basics/memoryerror: Add test for out-of-memory using realloc. --- tests/basics/memoryerror.py | 7 +++++++ tests/basics/memoryerror.py.exp | 1 + 2 files changed, 8 insertions(+) diff --git a/tests/basics/memoryerror.py b/tests/basics/memoryerror.py index ba145b7d4e..18053f097a 100644 --- a/tests/basics/memoryerror.py +++ b/tests/basics/memoryerror.py @@ -1,6 +1,13 @@ +# test out-of-memory with malloc l = list(range(1000)) try: 1000000000 * l except MemoryError: print('MemoryError') print(len(l), l[0], l[-1]) + +# test out-of-memory with realloc +try: + [].extend(range(1000000000)) +except MemoryError: + print('MemoryError') diff --git a/tests/basics/memoryerror.py.exp b/tests/basics/memoryerror.py.exp index c41e8c1a6a..3d6c7f0009 100644 --- a/tests/basics/memoryerror.py.exp +++ b/tests/basics/memoryerror.py.exp @@ -1,2 +1,3 @@ MemoryError 1000 0 999 +MemoryError From 82dc5c1d8c90c45ce93bbb41292df5e420642448 Mon Sep 17 00:00:00 2001 From: "Peter D. Gray" Date: Wed, 20 Dec 2017 10:45:22 -0500 Subject: [PATCH 208/828] stm32: Use corrected capitalization of HAL_SD_CardStateTypedef. It was originally TypeDef. STM32L4 only supports Typedef and F4/F7 have legacy macros in stm32_hal_legacy.h to support both. --- ports/stm32/sdcard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index 484426b846..a54e05011c 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -251,7 +251,7 @@ STATIC HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd, uint32_t tim } // Wait for SD card to complete the operation for (;;) { - HAL_SD_CardStateTypeDef state = HAL_SD_GetCardState(sd); + HAL_SD_CardStateTypedef state = HAL_SD_GetCardState(sd); if (state == HAL_SD_CARD_TRANSFER) { return HAL_OK; } From c73360bfdbecb0e2143147a7e7223c8161938456 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 22 Dec 2017 15:20:42 +1100 Subject: [PATCH 209/828] stm32: Allow to build a board without any hardware I2C ports defined. This patch adds in internal config value MICROPY_HW_ENABLE_HW_I2C that is automatically configured, and enabled only if one or more hardware I2C ports are defined in the mpconfigboard.h file. If none are defined then the pyb.I2C class is excluded from the build, along with all supporting code. The machine.I2C class will still be available for software I2C. Disabling all hardware I2C on an F4 board saves around 10,000 bytes of code and 200 bytes of RAM. --- ports/stm32/i2c.c | 4 ++++ ports/stm32/machine_i2c.c | 4 ++++ ports/stm32/main.c | 3 +++ ports/stm32/modpyb.c | 2 ++ ports/stm32/mpconfigport.h | 12 +++++++++++- 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index b22787cab5..e255cbc6b2 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -36,6 +36,8 @@ #include "dma.h" #include "i2c.h" +#if MICROPY_HW_ENABLE_HW_I2C + /// \moduleref pyb /// \class I2C - a two-wire serial protocol /// @@ -1033,3 +1035,5 @@ const mp_obj_type_t pyb_i2c_type = { .make_new = pyb_i2c_make_new, .locals_dict = (mp_obj_dict_t*)&pyb_i2c_locals_dict, }; + +#endif // MICROPY_HW_ENABLE_HW_I2C diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c index 1be2151e3b..1018a9b1a5 100644 --- a/ports/stm32/machine_i2c.c +++ b/ports/stm32/machine_i2c.c @@ -34,6 +34,8 @@ #include "genhdr/pins.h" #include "i2c.h" +#if MICROPY_HW_ENABLE_HW_I2C + STATIC const mp_obj_type_t machine_hard_i2c_type; #if defined(MCU_SERIES_F4) @@ -548,3 +550,5 @@ STATIC const mp_obj_type_t machine_hard_i2c_type = { .protocol = &machine_hard_i2c_p, .locals_dict = (mp_obj_dict_t*)&mp_machine_soft_i2c_locals_dict, }; + +#endif // MICROPY_HW_ENABLE_HW_I2C diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 9a83f9f363..352c09bcd4 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -556,7 +556,10 @@ soft_reset: rng_init0(); #endif + #if MICROPY_HW_ENABLE_HW_I2C i2c_init0(); + #endif + spi_init0(); pyb_usb_init0(); diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c index 81cbdcc191..4d186e2787 100644 --- a/ports/stm32/modpyb.c +++ b/ports/stm32/modpyb.c @@ -203,7 +203,9 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { #if defined(MICROPY_HW_LED1) { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pyb_led_type) }, #endif + #if MICROPY_HW_ENABLE_HW_I2C { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&pyb_i2c_type) }, + #endif { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&pyb_spi_type) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) }, #if MICROPY_HW_ENABLE_CAN diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 51d4425616..6fa286b262 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -131,7 +131,6 @@ #define MICROPY_PY_MACHINE_PULSE (1) #define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new #define MICROPY_PY_MACHINE_I2C (1) -#define MICROPY_PY_MACHINE_I2C_MAKE_NEW machine_hard_i2c_make_new #define MICROPY_PY_MACHINE_SPI (1) #define MICROPY_PY_MACHINE_SPI_MSB (SPI_FIRSTBIT_MSB) #define MICROPY_PY_MACHINE_SPI_LSB (SPI_FIRSTBIT_LSB) @@ -245,6 +244,17 @@ extern const struct _mp_obj_module_t mp_module_onewire; #define MICROPY_HW_MAX_UART (6) #endif +// enable hardware I2C if there are any peripherals defined +#define MICROPY_HW_ENABLE_HW_I2C ( \ + defined(MICROPY_HW_I2C1_SCL) \ + || defined(MICROPY_HW_I2C2_SCL) \ + || defined(MICROPY_HW_I2C3_SCL) \ + || defined(MICROPY_HW_I2C4_SCL) \ +) +#if MICROPY_HW_ENABLE_HW_I2C +#define MICROPY_PY_MACHINE_I2C_MAKE_NEW machine_hard_i2c_make_new +#endif + #define MP_STATE_PORT MP_STATE_VM #define MICROPY_PORT_ROOT_POINTERS \ From 7a46d9ae7313d4f92e9c32bf4dcc1e161a56d7ff Mon Sep 17 00:00:00 2001 From: "Peter D. Gray" Date: Wed, 20 Dec 2017 10:31:05 -0500 Subject: [PATCH 210/828] stm32/uart: Add support for 7-bit modes: 7N1 and 7N2. --- ports/stm32/uart.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index 0b46d4f040..b2962984f2 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -500,7 +500,14 @@ STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k if (!self->is_enabled) { mp_printf(print, "UART(%u)", self->uart_id); } else { - mp_int_t bits = (self->uart.Init.WordLength == UART_WORDLENGTH_8B ? 8 : 9); + mp_int_t bits; + switch (self->uart.Init.WordLength) { + #ifdef UART_WORDLENGTH_7B + case UART_WORDLENGTH_7B: bits = 7; break; + #endif + case UART_WORDLENGTH_8B: bits = 8; break; + case UART_WORDLENGTH_9B: default: bits = 9; break; + } if (self->uart.Init.Parity != UART_PARITY_NONE) { bits -= 1; } @@ -580,6 +587,10 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const init->WordLength = UART_WORDLENGTH_8B; } else if (bits == 9) { init->WordLength = UART_WORDLENGTH_9B; + #ifdef UART_WORDLENGTH_7B + } else if (bits == 7) { + init->WordLength = UART_WORDLENGTH_7B; + #endif } else { mp_raise_ValueError("unsupported combination of bits and parity"); } From f16c775a0782961a841f77cc48a789b3246d7ef7 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Sun, 10 Dec 2017 18:25:33 +0100 Subject: [PATCH 211/828] esp32/README: Update toolchain setup. --- ports/esp32/Makefile | 8 ++++++-- ports/esp32/README.md | 44 +++++++++++++++++++++---------------------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 2fa8c1c506..6bf212964c 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -21,19 +21,23 @@ FLASH_FREQ ?= 40m FLASH_SIZE ?= 4MB CROSS_COMPILE ?= xtensa-esp32-elf- +ESPIDF_SUPHASH := 2c95a77cf93781f296883d5dbafcdc18e4389656 + # paths to ESP IDF and its components ifeq ($(ESPIDF),) ifneq ($(IDF_PATH),) ESPIDF = $(IDF_PATH) else -$(error Please configure the ESPIDF variable) +$(info The ESPIDF variable has not been set, please set it to the root of the esp-idf repository.) +$(info See README.md for installation instructions.) +$(info Supported git hash: $(ESPIDF_SUPHASH)) +$(error ESPIDF not set) endif endif ESPCOMP = $(ESPIDF)/components ESPTOOL ?= $(ESPCOMP)/esptool_py/esptool/esptool.py # verify the ESP IDF version -ESPIDF_SUPHASH := 2c95a77cf93781f296883d5dbafcdc18e4389656 ESPIDF_CURHASH := $(shell git -C $(ESPIDF) show -s --pretty=format:'%H') ifneq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH)) $(info ** WARNING **) diff --git a/ports/esp32/README.md b/ports/esp32/README.md index 5c0eb813d6..ffd651c458 100644 --- a/ports/esp32/README.md +++ b/ports/esp32/README.md @@ -26,34 +26,28 @@ There are two main components that are needed to build the firmware: different to the compiler used by the ESP8266) - the Espressif IDF (IoT development framework, aka SDK) -Instructions for setting up both of these components are provided by the -ESP-IDF itself, which is found at https://github.com/espressif/esp-idf . -Follow the guide "Setting Up ESP-IDF", for Windows, Mac or Linux. You -only need to perform up to "Step 2" of the guide, by which stage you -should have installed the cross-compile and cloned the ESP-IDF repository. +The ESP-IDF changes quickly and MicroPython only supports a certain version. The +git hash of this version can be found by running `make` without a configured +`ESPIDF`. Then you can fetch only the given esp-idf using the following command: + + $ git clone https://github.com/espressif/esp-idf.git + $ git checkout + $ git submodule update --recursive + +The binary toolchain (binutils, gcc, etc.) can be installed using the following +guides: + + * [Linux installation](https://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html) + * [MacOS installation](https://esp-idf.readthedocs.io/en/latest/get-started/macos-setup.html) + * [Windows installation](https://esp-idf.readthedocs.io/en/latest/get-started/windows-setup.html) If you are on a Windows machine then the [Windows Subsystem for Linux](https://msdn.microsoft.com/en-au/commandline/wsl/install_guide) is the most efficient way to install the ESP32 toolchain and build the project. If you use WSL then follow the -[Linux guidelines](http://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html) +[Linux guidelines](https://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html) for the ESP-IDF instead of the Windows ones. -Be advised that the ESP-IDF is still undergoing changes and only some -versions are supported. To find which build is compatible refer to the line -in the makefile containing the following: -``` -ESPIDF_SUPHASH := -``` -After finishing "Step 2" you can roll back your current build of -the ESP-IDF (and update the submodules accordingly) using: -``` -$ git checkout -$ git submodule update --recursive -``` -Note that you will get a warning when building the code if the ESP-IDF -version is incorrect. - The Espressif ESP-IDF instructions above only install pyserial for Python 2, so if you're running Python 3 or a non-system Python you'll also need to install `pyserial` (or `esptool`) so that the Makefile can flash the board @@ -64,7 +58,13 @@ $ pip install pyserial Once everything is set up you should have a functioning toolchain with prefix xtensa-esp32-elf- (or otherwise if you configured it differently) -as well as a copy of the ESP-IDF repository. +as well as a copy of the ESP-IDF repository. You will need to update your `PATH` +environment variable to include the ESP32 toolchain. For example, you can issue +the following commands on (at least) Linux: + + $ export PATH=$PATH:$HOME/esp/crosstool-NG/builds/xtensa-esp32-elf/bin + +You cam put this command in your `.profile` or `.bash_login`. You then need to set the `ESPIDF` environment/makefile variable to point to the root of the ESP-IDF repository. You can set the variable in your PATH, From b90f51f86a0824d646131538320d0405ab3d0187 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Wed, 20 Dec 2017 01:15:26 +0100 Subject: [PATCH 212/828] drivers/sdcard: Support old SD cards (<=2GB). --- drivers/sdcard/sdcard.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/sdcard/sdcard.py b/drivers/sdcard/sdcard.py index 75a0c501ee..fedb76f02c 100644 --- a/drivers/sdcard/sdcard.py +++ b/drivers/sdcard/sdcard.py @@ -96,9 +96,14 @@ class SDCard: raise OSError("no response from SD card") csd = bytearray(16) self.readinto(csd) - if csd[0] & 0xc0 != 0x40: + if csd[0] & 0xc0 == 0x40: # CSD version 2.0 + self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 2014 + elif csd[0] & 0xc0 == 0x00: # CSD version 1.0 (old, <=2GB) + c_size = csd[6] & 0b11 | csd[7] << 2 | (csd[8] & 0b11000000) << 4 + c_size_mult = ((csd[9] & 0b11) << 1) | csd[10] >> 7 + self.sectors = (c_size + 1) * (2 ** (c_size_mult + 2)) + else: raise OSError("SD card CSD format not supported") - self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 2014 #print('sectors', self.sectors) # CMD16: set block length to 512 bytes From 9bcdb0acd1ea059533ba01d8c8ccfd12adeb0eee Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 22 Dec 2017 17:16:42 +1100 Subject: [PATCH 213/828] esp8266/Makefile: Remove commented-out unused lines. These were copied from the stm32 port (then stmhal) at the very beginning of this port, with the anticipation that the esp8266 port would have board definition files with a list of valid pins and their names. But that has not been implemented and likely won't be, so remove the corresponding lines from the Makefile. --- ports/esp8266/Makefile | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile index 95236a8d91..9d6e502c78 100644 --- a/ports/esp8266/Makefile +++ b/ports/esp8266/Makefile @@ -143,7 +143,6 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) -#OBJ += $(BUILD)/pins_$(BOARD).o # List of sources for qstr extraction SRC_QSTR += $(SRC_C) $(EXTMOD_SRC_C) $(LIB_SRC_C) $(DRIVERS_SRC_C) @@ -195,32 +194,6 @@ ota: rm -f $(BUILD)/firmware.elf $(BUILD)/firmware.elf*.bin $(MAKE) LDSCRIPT=esp8266_ota.ld FWBIN=$(BUILD)/firmware-ota.bin -#MAKE_PINS = boards/make-pins.py -#BOARD_PINS = boards/$(BOARD)/pins.csv -#AF_FILE = boards/stm32f4xx_af.csv -#PREFIX_FILE = boards/stm32f4xx_prefix.c -#GEN_PINS_SRC = $(BUILD)/pins_$(BOARD).c -#GEN_PINS_HDR = $(HEADER_BUILD)/pins.h -#GEN_PINS_QSTR = $(BUILD)/pins_qstr.h -#GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins_af_const.h -#GEN_PINS_AF_PY = $(BUILD)/pins_af.py - -# Making OBJ use an order-only depenedency on the generated pins.h file -# has the side effect of making the pins.h file before we actually compile -# any of the objects. The normal dependency generation will deal with the -# case when pins.h is modified. But when it doesn't exist, we don't know -# which source files might need it. -#$(OBJ): | $(HEADER_BUILD)/pins.h - -# Use a pattern rule here so that make will only call make-pins.py once to make -# both pins_$(BOARD).c and pins.h -#$(BUILD)/%_$(BOARD).c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%_af_const.h $(BUILD)/%_qstr.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD) -# $(ECHO) "Create $@" -# $(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) --qstr $(GEN_PINS_QSTR) --af-const $(GEN_PINS_AF_CONST) --af-py $(GEN_PINS_AF_PY) > $(GEN_PINS_SRC) -# -#$(BUILD)/pins_$(BOARD).o: $(BUILD)/pins_$(BOARD).c -# $(call compile_c) - include $(TOP)/py/mkrules.mk axtls: $(BUILD)/libaxtls.a From d32417c0969a9cea5edec0858e147102a5720ed2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 23 Dec 2017 19:01:23 +1100 Subject: [PATCH 214/828] stm32/uart: Support board configs with CTS/RTS on UART6. --- ports/stm32/uart.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index b2962984f2..659aa9943b 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -241,6 +241,16 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { irqn = USART6_IRQn; pins[0] = &MICROPY_HW_UART6_TX; pins[1] = &MICROPY_HW_UART6_RX; + #if defined(MICROPY_HW_UART6_RTS) + if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_RTS) { + pins[2] = &MICROPY_HW_UART6_RTS; + } + #endif + #if defined(MICROPY_HW_UART6_CTS) + if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) { + pins[3] = &MICROPY_HW_UART6_CTS; + } + #endif __USART6_CLK_ENABLE(); break; #endif From 008e1788e8a08261bb7c15976d18c946dd3b2259 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 23 Dec 2017 19:22:52 +1100 Subject: [PATCH 215/828] stm32/i2c: Fix bug with I2C4 initialisation. --- ports/stm32/i2c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index e255cbc6b2..5bbc889c1a 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -222,7 +222,7 @@ void i2c_init0(void) { #endif #if defined(MICROPY_HW_I2C4_SCL) memset(&I2CHandle4, 0, sizeof(I2C_HandleTypeDef)); - I2CHandle3.Instance = I2C4; + I2CHandle4.Instance = I2C4; #endif } @@ -258,7 +258,7 @@ void i2c_init(I2C_HandleTypeDef *i2c) { i2c_unit = 4; scl_pin = &MICROPY_HW_I2C4_SCL; sda_pin = &MICROPY_HW_I2C4_SDA; - __I2C3_CLK_ENABLE(); + __I2C4_CLK_ENABLE(); #endif } else { // I2C does not exist for this board (shouldn't get here, should be checked by caller) From b806889512a8c7f817ff23c7bf572c971acc9763 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 23 Dec 2017 19:23:35 +1100 Subject: [PATCH 216/828] stm32/i2c: Support more I2C baudrates for F746, and more F7 MCUs. --- ports/stm32/i2c.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index 5bbc889c1a..5a6edc3297 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -136,11 +136,17 @@ const pyb_i2c_obj_t pyb_i2c_obj[] = { // The value 0x40912732 was obtained from the DISCOVERY_I2Cx_TIMING constant // defined in the STM32F7Cube file Drivers/BSP/STM32F746G-Discovery/stm32f7456g_discovery.h -#define MICROPY_HW_I2C_BAUDRATE_TIMING {{100000, 0x40912732}} -#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (100000) -#define MICROPY_HW_I2C_BAUDRATE_MAX (100000) +#define MICROPY_HW_I2C_BAUDRATE_TIMING { \ + {100000, 0x40912732}, \ + {400000, 0x10911823}, \ + {1000000, 0x00611116}, \ + } +#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (400000) +#define MICROPY_HW_I2C_BAUDRATE_MAX (1000000) -#elif defined(STM32F767xx) || defined(STM32F769xx) +#elif defined(STM32F722xx) || defined(STM32F723xx) \ + || defined(STM32F732xx) || defined(STM32F733xx) \ + || defined(STM32F767xx) || defined(STM32F769xx) // These timing values are for f_I2CCLK=54MHz and are only approximate #define MICROPY_HW_I2C_BAUDRATE_TIMING { \ From 5de064fbd056944e393be9355855eee6562fecdb Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 23 Dec 2017 21:21:08 +0200 Subject: [PATCH 217/828] docs/library/index: Elaborate uPy libraries intro. --- docs/library/index.rst | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/docs/library/index.rst b/docs/library/index.rst index b141abf1e6..af1a0ff697 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -9,34 +9,36 @@ MicroPython libraries * MicroPython implements a subset of Python functionality for each module. * To ease extensibility, MicroPython versions of standard Python modules - usually have ``u`` (micro) prefix. + usually have ``u`` ("micro") prefix. * Any particular MicroPython variant or port may miss any feature/function - described in this general documentation, due to resource constraints. + described in this general documentation (due to resource constraints or + other limitations). This chapter describes modules (function and class libraries) which are built -into MicroPython. There are a few categories of modules: +into MicroPython. There are a few categories of such modules: * Modules which implement a subset of standard Python functionality and are not intended to be extended by the user. * Modules which implement a subset of Python functionality, with a provision for extension by the user (via Python code). * Modules which implement MicroPython extensions to the Python standard libraries. -* Modules specific to a particular port and thus not portable. +* Modules specific to a particular `MicroPython port` and thus not portable. -Note about the availability of modules and their contents: This documentation +Note about the availability of the modules and their contents: This documentation in general aspires to describe all modules and functions/classes which are -implemented in MicroPython. However, MicroPython is highly configurable, and +implemented in MicroPython project. However, MicroPython is highly configurable, and each port to a particular board/embedded system makes available only a subset of MicroPython libraries. For officially supported ports, there is an effort to either filter out non-applicable items, or mark individual descriptions with "Availability:" clauses describing which ports provide a given feature. + With that in mind, please still be warned that some functions/classes -in a module (or even the entire module) described in this documentation may be -unavailable in a particular build of MicroPython on a particular board. The +in a module (or even the entire module) described in this documentation **may be +unavailable** in a particular build of MicroPython on a particular system. The best place to find general information of the availability/non-availability of a particular feature is the "General Information" section which contains -information pertaining to a specific port. +information pertaining to a specific `MicroPython port`. Beyond the built-in libraries described in this documentation, many more modules from the Python standard library, as well as further MicroPython @@ -58,9 +60,9 @@ what done by the `micropython-lib` project mentioned above). On some embedded platforms, where it may be cumbersome to add Python-level wrapper modules to achieve naming compatibility with CPython, micro-modules are available both by their u-name, and also by their non-u-name. The -non-u-name can be overridden by a file of that name in your package path. -For example, ``import json`` will first search for a file ``json.py`` or -directory ``json`` and load that package if it is found. If nothing is found, +non-u-name can be overridden by a file of that name in your library path (``sys.path``). +For example, ``import json`` will first search for a file ``json.py`` (or package +directory ``json``) and load that module if it is found. If nothing is found, it will fallback to loading the built-in ``ujson`` module. .. only:: port_unix From d9977a8ad9c257005455ca8cbc7913584f2394a6 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 26 Dec 2017 14:46:16 +0200 Subject: [PATCH 218/828] zephyr/Makefile: clean: Clean libmicropython.a too. --- ports/zephyr/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr/Makefile b/ports/zephyr/Makefile index 2064fcef7e..49a6f67188 100644 --- a/ports/zephyr/Makefile +++ b/ports/zephyr/Makefile @@ -82,7 +82,7 @@ build/genhdr/qstr.i.last: | $(Z_EXPORTS) LIBMICROPYTHON_EXTRA_CMD = -$(RM) -f outdir/$(OUTDIR_PREFIX)/zephyr.lnk # MicroPython's global clean cleans everything, fast -CLEAN_EXTRA = outdir prj_*_merged.conf +CLEAN_EXTRA = outdir libmicropython.a prj_*_merged.conf # Clean Zephyr things in Zephyr way z_clean: From 096e967aad6df760c16de4878b8b2eea02330011 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 26 Dec 2017 18:39:51 +0200 Subject: [PATCH 219/828] Revert "py/nlr: Factor out common NLR code to generic functions." This reverts commit 6a3a742a6c9caaa2be0fd0aac7a5df4ac816081c. The above commit has number of faults starting from the motivation down to the actual implementation. 1. Faulty implementation. The original code contained functions like: NORETURN void nlr_jump(void *val) { nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); nlr_buf_t *top = *top_ptr; ... __asm volatile ( "mov %0, %%edx \n" // %edx points to nlr_buf "mov 28(%%edx), %%esi \n" // load saved %esi "mov 24(%%edx), %%edi \n" // load saved %edi "mov 20(%%edx), %%ebx \n" // load saved %ebx "mov 16(%%edx), %%esp \n" // load saved %esp "mov 12(%%edx), %%ebp \n" // load saved %ebp "mov 8(%%edx), %%eax \n" // load saved %eip "mov %%eax, (%%esp) \n" // store saved %eip to stack "xor %%eax, %%eax \n" // clear return register "inc %%al \n" // increase to make 1, non-local return "ret \n" // return : // output operands : "r"(top) // input operands : // clobbered registers ); } Which clearly stated that C-level variable should be a parameter of the assembly, whcih then moved it into correct register. Whereas now it's: NORETURN void nlr_jump_tail(nlr_buf_t *top) { (void)top; __asm volatile ( "mov 28(%edx), %esi \n" // load saved %esi "mov 24(%edx), %edi \n" // load saved %edi "mov 20(%edx), %ebx \n" // load saved %ebx "mov 16(%edx), %esp \n" // load saved %esp "mov 12(%edx), %ebp \n" // load saved %ebp "mov 8(%edx), %eax \n" // load saved %eip "mov %eax, (%esp) \n" // store saved %eip to stack "xor %eax, %eax \n" // clear return register "inc %al \n" // increase to make 1, non-local return "ret \n" // return ); for (;;); // needed to silence compiler warning } Which just tries to perform operations on a completely random register (edx in this case). The outcome is the expected: saving the pure random luck of the compiler putting the right value in the random register above, there's a crash. 2. Non-critical assessment. The original commit message says "There is a small overhead introduced (typically 1 machine instruction)". That machine instruction is a call if a compiler doesn't perform tail optimization (happens regularly), and it's 1 instruction only with the broken code shown above, fixing it requires adding more. With inefficiencies already presented in the NLR code, the overhead becomes "considerable" (several times more than 1%), not "small". The commit message also says "This eliminates duplicated code.". An obvious way to eliminate duplication would be to factor out common code to macros, not introduce overhead and breakage like above. 3. Faulty motivation. All this started with a report of warnings/errors happening for a niche compiler. It could have been solved in one the direct ways: a) fixing it just for affected compiler(s); b) rewriting it in proper assembly (like it was before BTW); c) by not doing anything at all, MICROPY_NLR_SETJMP exists exactly to address minor-impact cases like thar (where a) or b) are not applicable). Instead, a backwards "solution" was put forward, leading to all the issues above. The best action thus appears to be revert and rework, not trying to work around what went haywire in the first place. --- py/nlr.c | 74 ------------------------------------------------- py/nlr.h | 75 ++++++++++++++++++++++++++------------------------ py/nlrsetjmp.c | 10 ++++++- py/nlrthumb.c | 38 +++++++++++++++++++++++-- py/nlrx64.c | 70 +++++++++++++++++++++++++++++----------------- py/nlrx86.c | 63 +++++++++++++++++++++++++++++++++--------- py/nlrxtensa.c | 34 +++++++++++++++++++---- py/py.mk | 1 - 8 files changed, 206 insertions(+), 159 deletions(-) delete mode 100644 py/nlr.c diff --git a/py/nlr.c b/py/nlr.c deleted file mode 100644 index e4d6d10c0b..0000000000 --- a/py/nlr.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2013-2017 Damien P. George - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "py/mpstate.h" - -// Helper macros to save/restore the pystack state -#if MICROPY_ENABLE_PYSTACK -#define MP_NLR_SAVE_PYSTACK(nlr_buf) (nlr_buf)->pystack = MP_STATE_THREAD(pystack_cur) -#define MP_NLR_RESTORE_PYSTACK(nlr_buf) MP_STATE_THREAD(pystack_cur) = (nlr_buf)->pystack -#else -#define MP_NLR_SAVE_PYSTACK(nlr_buf) (void)nlr_buf -#define MP_NLR_RESTORE_PYSTACK(nlr_buf) (void)nlr_buf -#endif - -#if !MICROPY_NLR_SETJMP -// When not using setjmp, nlr_push_tail is called from inline asm so needs special care -#if MICROPY_NLR_X86 && (defined(_WIN32) || defined(__CYGWIN__)) -// On these 32-bit platforms make sure nlr_push_tail doesn't have a leading underscore -unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail"); -#else -// LTO can't see inside inline asm functions so explicitly mark nlr_push_tail as used -__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); -#endif -#endif - -unsigned int nlr_push_tail(nlr_buf_t *nlr) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - nlr->prev = *top; - MP_NLR_SAVE_PYSTACK(nlr); - *top = nlr; - return 0; // normal return -} - -void nlr_pop(void) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - *top = (*top)->prev; -} - -NORETURN void nlr_jump(void *val) { - nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); - nlr_buf_t *top = *top_ptr; - if (top == NULL) { - nlr_jump_fail(val); - } - - top->ret_val = val; - MP_NLR_RESTORE_PYSTACK(top); - *top_ptr = top->prev; - - nlr_jump_tail(top); -} diff --git a/py/nlr.h b/py/nlr.h index 012a73c311..1235f14609 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -30,29 +30,29 @@ // exception handling, basically a stack of setjmp/longjmp buffers #include +#include #include #include "py/mpconfig.h" -// If MICROPY_NLR_SETJMP is not enabled then auto-detect the machine arch -// Allow a port to set MICROPY_NLR_NUM_REGS to define their own implementation -#if !MICROPY_NLR_SETJMP && !defined(MICROPY_NLR_NUM_REGS) +typedef struct _nlr_buf_t nlr_buf_t; +struct _nlr_buf_t { + // the entries here must all be machine word size + nlr_buf_t *prev; + void *ret_val; // always a concrete object (an exception instance) +#if !defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP #if defined(__i386__) - #define MICROPY_NLR_X86 (1) - #define MICROPY_NLR_NUM_REGS (6) + void *regs[6]; #elif defined(__x86_64__) - #define MICROPY_NLR_X64 (1) - #if defined(__CYGWIN__) - #define MICROPY_NLR_NUM_REGS (12) - #else - #define MICROPY_NLR_NUM_REGS (8) - #endif + #if defined(__CYGWIN__) + void *regs[12]; + #else + void *regs[8]; + #endif #elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__) - #define MICROPY_NLR_THUMB (1) - #define MICROPY_NLR_NUM_REGS (10) + void *regs[10]; #elif defined(__xtensa__) - #define MICROPY_NLR_XTENSA (1) - #define MICROPY_NLR_NUM_REGS (10) + void *regs[10]; #else #define MICROPY_NLR_SETJMP (1) //#warning "No native NLR support for this arch, using setjmp implementation" @@ -60,39 +60,41 @@ #endif #if MICROPY_NLR_SETJMP -#include -#endif - -typedef struct _nlr_buf_t nlr_buf_t; -struct _nlr_buf_t { - // the entries here must all be machine word size - nlr_buf_t *prev; - void *ret_val; // always a concrete object (an exception instance) - - #if MICROPY_NLR_SETJMP jmp_buf jmpbuf; - #else - void *regs[MICROPY_NLR_NUM_REGS]; - #endif +#endif #if MICROPY_ENABLE_PYSTACK void *pystack; #endif }; -#if MICROPY_NLR_SETJMP -// nlr_push() must be defined as a macro, because "The stack context will be -// invalidated if the function which called setjmp() returns." -// For this case it is safe to call nlr_push_tail() first. -#define nlr_push(buf) (nlr_push_tail(buf), setjmp((buf)->jmpbuf)) +// Helper macros to save/restore the pystack state +#if MICROPY_ENABLE_PYSTACK +#define MP_NLR_SAVE_PYSTACK(nlr_buf) (nlr_buf)->pystack = MP_STATE_THREAD(pystack_cur) +#define MP_NLR_RESTORE_PYSTACK(nlr_buf) MP_STATE_THREAD(pystack_cur) = (nlr_buf)->pystack #else -unsigned int nlr_push(nlr_buf_t *); +#define MP_NLR_SAVE_PYSTACK(nlr_buf) (void)nlr_buf +#define MP_NLR_RESTORE_PYSTACK(nlr_buf) (void)nlr_buf #endif -unsigned int nlr_push_tail(nlr_buf_t *top); +#if MICROPY_NLR_SETJMP +#include "py/mpstate.h" + +NORETURN void nlr_setjmp_jump(void *val); +// nlr_push() must be defined as a macro, because "The stack context will be +// invalidated if the function which called setjmp() returns." +#define nlr_push(buf) ( \ + (buf)->prev = MP_STATE_THREAD(nlr_top), \ + MP_NLR_SAVE_PYSTACK(buf), \ + MP_STATE_THREAD(nlr_top) = (buf), \ + setjmp((buf)->jmpbuf)) +#define nlr_pop() { MP_STATE_THREAD(nlr_top) = MP_STATE_THREAD(nlr_top)->prev; } +#define nlr_jump(val) nlr_setjmp_jump(val) +#else +unsigned int nlr_push(nlr_buf_t *); void nlr_pop(void); NORETURN void nlr_jump(void *val); -NORETURN void nlr_jump_tail(nlr_buf_t *top); +#endif // This must be implemented by a port. It's called by nlr_jump // if no nlr buf has been pushed. It must not return, but rather @@ -121,6 +123,7 @@ NORETURN void nlr_jump_fail(void *val); /* #define nlr_push(val) \ printf("nlr_push: before: nlr_top=%p, val=%p\n", MP_STATE_THREAD(nlr_top), val),assert(MP_STATE_THREAD(nlr_top) != val),nlr_push(val) +#endif */ #endif diff --git a/py/nlrsetjmp.c b/py/nlrsetjmp.c index 6ddad37934..63376a5537 100644 --- a/py/nlrsetjmp.c +++ b/py/nlrsetjmp.c @@ -28,7 +28,15 @@ #if MICROPY_NLR_SETJMP -NORETURN void nlr_jump_tail(nlr_buf_t *top) { +void nlr_setjmp_jump(void *val) { + nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); + nlr_buf_t *top = *top_ptr; + if (top == NULL) { + nlr_jump_fail(val); + } + top->ret_val = val; + MP_NLR_RESTORE_PYSTACK(top); + *top_ptr = top->prev; longjmp(top->jmpbuf, 1); } diff --git a/py/nlrthumb.c b/py/nlrthumb.c index 4edd1456dd..eab5759f21 100644 --- a/py/nlrthumb.c +++ b/py/nlrthumb.c @@ -26,7 +26,7 @@ #include "py/mpstate.h" -#if MICROPY_NLR_THUMB +#if (!defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP) && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) #undef nlr_push @@ -37,6 +37,7 @@ // r4-r11, r13=sp __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { + __asm volatile ( "str r4, [r0, #12] \n" // store r4 into nlr_buf "str r5, [r0, #16] \n" // store r5 into nlr_buf @@ -74,10 +75,36 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { "b nlr_push_tail \n" // do the rest in C #endif ); + + return 0; // needed to silence compiler warning } -NORETURN __attribute__((naked)) void nlr_jump_tail(nlr_buf_t *top) { +__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { + nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); + nlr->prev = *top; + MP_NLR_SAVE_PYSTACK(nlr); + *top = nlr; + return 0; // normal return +} + +void nlr_pop(void) { + nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); + *top = (*top)->prev; +} + +NORETURN __attribute__((naked)) void nlr_jump(void *val) { + nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); + nlr_buf_t *top = *top_ptr; + if (top == NULL) { + nlr_jump_fail(val); + } + + top->ret_val = val; + MP_NLR_RESTORE_PYSTACK(top); + *top_ptr = top->prev; + __asm volatile ( + "mov r0, %0 \n" // r0 points to nlr_buf "ldr r4, [r0, #12] \n" // load r4 from nlr_buf "ldr r5, [r0, #16] \n" // load r5 from nlr_buf "ldr r6, [r0, #20] \n" // load r6 from nlr_buf @@ -106,7 +133,12 @@ NORETURN __attribute__((naked)) void nlr_jump_tail(nlr_buf_t *top) { #endif "movs r0, #1 \n" // return 1, non-local return "bx lr \n" // return + : // output operands + : "r"(top) // input operands + : // clobbered registers ); + + for (;;); // needed to silence compiler warning } -#endif // MICROPY_NLR_THUMB +#endif // (!defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP) && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) diff --git a/py/nlrx64.c b/py/nlrx64.c index e7e2e14748..ddcd761665 100644 --- a/py/nlrx64.c +++ b/py/nlrx64.c @@ -26,7 +26,7 @@ #include "py/mpstate.h" -#if MICROPY_NLR_X64 +#if !MICROPY_NLR_SETJMP && defined(__x86_64__) #undef nlr_push @@ -39,6 +39,8 @@ #define NLR_OS_WINDOWS 0 #endif +__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); + unsigned int nlr_push(nlr_buf_t *nlr) { (void)nlr; @@ -86,38 +88,54 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; // needed to silence compiler warning } -NORETURN void nlr_jump_tail(nlr_buf_t *top) { - (void)top; +__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { + nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); + nlr->prev = *top; + MP_NLR_SAVE_PYSTACK(nlr); + *top = nlr; + return 0; // normal return +} + +void nlr_pop(void) { + nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); + *top = (*top)->prev; +} + +NORETURN void nlr_jump(void *val) { + nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); + nlr_buf_t *top = *top_ptr; + if (top == NULL) { + nlr_jump_fail(val); + } + + top->ret_val = val; + MP_NLR_RESTORE_PYSTACK(top); + *top_ptr = top->prev; __asm volatile ( + "movq %0, %%rcx \n" // %rcx points to nlr_buf #if NLR_OS_WINDOWS - "movq 88(%rcx), %rsi \n" // load saved %rsi - "movq 80(%rcx), %rdi \n" // load saved %rdr - "movq 72(%rcx), %r15 \n" // load saved %r15 - "movq 64(%rcx), %r14 \n" // load saved %r14 - "movq 56(%rcx), %r13 \n" // load saved %r13 - "movq 48(%rcx), %r12 \n" // load saved %r12 - "movq 40(%rcx), %rbx \n" // load saved %rbx - "movq 32(%rcx), %rsp \n" // load saved %rsp - "movq 24(%rcx), %rbp \n" // load saved %rbp - "movq 16(%rcx), %rax \n" // load saved %rip - #else - "movq 72(%rdi), %r15 \n" // load saved %r15 - "movq 64(%rdi), %r14 \n" // load saved %r14 - "movq 56(%rdi), %r13 \n" // load saved %r13 - "movq 48(%rdi), %r12 \n" // load saved %r12 - "movq 40(%rdi), %rbx \n" // load saved %rbx - "movq 32(%rdi), %rsp \n" // load saved %rsp - "movq 24(%rdi), %rbp \n" // load saved %rbp - "movq 16(%rdi), %rax \n" // load saved %rip + "movq 88(%%rcx), %%rsi \n" // load saved %rsi + "movq 80(%%rcx), %%rdi \n" // load saved %rdr #endif - "movq %rax, (%rsp) \n" // store saved %rip to stack - "xorq %rax, %rax \n" // clear return register - "inc %al \n" // increase to make 1, non-local return + "movq 72(%%rcx), %%r15 \n" // load saved %r15 + "movq 64(%%rcx), %%r14 \n" // load saved %r14 + "movq 56(%%rcx), %%r13 \n" // load saved %r13 + "movq 48(%%rcx), %%r12 \n" // load saved %r12 + "movq 40(%%rcx), %%rbx \n" // load saved %rbx + "movq 32(%%rcx), %%rsp \n" // load saved %rsp + "movq 24(%%rcx), %%rbp \n" // load saved %rbp + "movq 16(%%rcx), %%rax \n" // load saved %rip + "movq %%rax, (%%rsp) \n" // store saved %rip to stack + "xorq %%rax, %%rax \n" // clear return register + "inc %%al \n" // increase to make 1, non-local return "ret \n" // return + : // output operands + : "r"(top) // input operands + : // clobbered registers ); for (;;); // needed to silence compiler warning } -#endif // MICROPY_NLR_X64 +#endif // !MICROPY_NLR_SETJMP && defined(__x86_64__) diff --git a/py/nlrx86.c b/py/nlrx86.c index cc37f72afb..3a27460eb6 100644 --- a/py/nlrx86.c +++ b/py/nlrx86.c @@ -26,13 +26,25 @@ #include "py/mpstate.h" -#if MICROPY_NLR_X86 +#if !MICROPY_NLR_SETJMP && defined(__i386__) #undef nlr_push // For reference, x86 callee save regs are: // ebx, esi, edi, ebp, esp, eip +#if defined(_WIN32) || defined(__CYGWIN__) +#define NLR_OS_WINDOWS 1 +#else +#define NLR_OS_WINDOWS 0 +#endif + +#if NLR_OS_WINDOWS +unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail"); +#else +__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); +#endif + unsigned int nlr_push(nlr_buf_t *nlr) { (void)nlr; @@ -58,23 +70,48 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; // needed to silence compiler warning } -NORETURN void nlr_jump_tail(nlr_buf_t *top) { - (void)top; +__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { + nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); + nlr->prev = *top; + MP_NLR_SAVE_PYSTACK(nlr); + *top = nlr; + return 0; // normal return +} + +void nlr_pop(void) { + nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); + *top = (*top)->prev; +} + +NORETURN void nlr_jump(void *val) { + nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); + nlr_buf_t *top = *top_ptr; + if (top == NULL) { + nlr_jump_fail(val); + } + + top->ret_val = val; + MP_NLR_RESTORE_PYSTACK(top); + *top_ptr = top->prev; __asm volatile ( - "mov 28(%edx), %esi \n" // load saved %esi - "mov 24(%edx), %edi \n" // load saved %edi - "mov 20(%edx), %ebx \n" // load saved %ebx - "mov 16(%edx), %esp \n" // load saved %esp - "mov 12(%edx), %ebp \n" // load saved %ebp - "mov 8(%edx), %eax \n" // load saved %eip - "mov %eax, (%esp) \n" // store saved %eip to stack - "xor %eax, %eax \n" // clear return register - "inc %al \n" // increase to make 1, non-local return + "mov %0, %%edx \n" // %edx points to nlr_buf + "mov 28(%%edx), %%esi \n" // load saved %esi + "mov 24(%%edx), %%edi \n" // load saved %edi + "mov 20(%%edx), %%ebx \n" // load saved %ebx + "mov 16(%%edx), %%esp \n" // load saved %esp + "mov 12(%%edx), %%ebp \n" // load saved %ebp + "mov 8(%%edx), %%eax \n" // load saved %eip + "mov %%eax, (%%esp) \n" // store saved %eip to stack + "xor %%eax, %%eax \n" // clear return register + "inc %%al \n" // increase to make 1, non-local return "ret \n" // return + : // output operands + : "r"(top) // input operands + : // clobbered registers ); for (;;); // needed to silence compiler warning } -#endif // MICROPY_NLR_X86 +#endif // !MICROPY_NLR_SETJMP && defined(__i386__) diff --git a/py/nlrxtensa.c b/py/nlrxtensa.c index 6b99182271..5a969fc87c 100644 --- a/py/nlrxtensa.c +++ b/py/nlrxtensa.c @@ -26,7 +26,7 @@ #include "py/mpstate.h" -#if MICROPY_NLR_XTENSA +#if !MICROPY_NLR_SETJMP && defined(__xtensa__) #undef nlr_push @@ -37,7 +37,6 @@ // a3-a7 = rest of args unsigned int nlr_push(nlr_buf_t *nlr) { - (void)nlr; __asm volatile ( "s32i.n a0, a2, 8 \n" // save regs... @@ -56,10 +55,32 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; // needed to silence compiler warning } -NORETURN void nlr_jump_tail(nlr_buf_t *top) { - (void)top; +__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { + nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); + nlr->prev = *top; + MP_NLR_SAVE_PYSTACK(nlr); + *top = nlr; + return 0; // normal return +} + +void nlr_pop(void) { + nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); + *top = (*top)->prev; +} + +NORETURN void nlr_jump(void *val) { + nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); + nlr_buf_t *top = *top_ptr; + if (top == NULL) { + nlr_jump_fail(val); + } + + top->ret_val = val; + MP_NLR_RESTORE_PYSTACK(top); + *top_ptr = top->prev; __asm volatile ( + "mov.n a2, %0 \n" // a2 points to nlr_buf "l32i.n a0, a2, 8 \n" // restore regs... "l32i.n a1, a2, 12 \n" "l32i.n a8, a2, 16 \n" @@ -72,9 +93,12 @@ NORETURN void nlr_jump_tail(nlr_buf_t *top) { "l32i.n a15, a2, 44 \n" "movi.n a2, 1 \n" // return 1, non-local return "ret.n \n" // return + : // output operands + : "r"(top) // input operands + : // clobbered registers ); for (;;); // needed to silence compiler warning } -#endif // MICROPY_NLR_XTENSA +#endif // !MICROPY_NLR_SETJMP && defined(__xtensa__) diff --git a/py/py.mk b/py/py.mk index de82a971bc..0b5d5f8c40 100644 --- a/py/py.mk +++ b/py/py.mk @@ -103,7 +103,6 @@ endif # py object files PY_O_BASENAME = \ mpstate.o \ - nlr.o \ nlrx86.o \ nlrx64.o \ nlrthumb.o \ From 7a9a73ee8466111f73a7de7d27568c1260d802ef Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 26 Dec 2017 20:16:08 +0200 Subject: [PATCH 220/828] zephyr/main: Remove unused do_str() function. The artifact of initial porting effort. --- ports/zephyr/main.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/ports/zephyr/main.c b/ports/zephyr/main.c index 8c64fdceea..58d127ec63 100644 --- a/ports/zephyr/main.c +++ b/ports/zephyr/main.c @@ -51,21 +51,6 @@ static char *stack_top; static char heap[MICROPY_HEAP_SIZE]; -void do_str(const char *src, mp_parse_input_kind_t input_kind) { - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); - qstr source_name = lex->source_name; - mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); - mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true); - mp_call_function_0(module_fun); - nlr_pop(); - } else { - // uncaught exception - mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); - } -} - void init_zephyr(void) { // We now rely on CONFIG_NET_APP_SETTINGS to set up bootstrap // network addresses. From 97cc48553828ed091325d0d3922eb4cd6c377221 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 28 Dec 2017 15:59:09 +1100 Subject: [PATCH 221/828] py/nlrthumb: Fix use of naked funcs, must only contain basic asm code. A function with a naked attribute must only contain basic inline asm statements and no C code. For nlr_push this means removing the "return 0" statement. But for some gcc versions this induces a compiler warning so the __builtin_unreachable() line needs to be added. For nlr_jump, this function contains a combination of C code and inline asm so cannot be naked. --- py/nlrthumb.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/py/nlrthumb.c b/py/nlrthumb.c index eab5759f21..18d31eb706 100644 --- a/py/nlrthumb.c +++ b/py/nlrthumb.c @@ -76,7 +76,10 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { #endif ); - return 0; // needed to silence compiler warning + #if defined(__GNUC__) + // Older versions of gcc give an error when naked functions don't return a value + __builtin_unreachable(); + #endif } __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { @@ -92,7 +95,7 @@ void nlr_pop(void) { *top = (*top)->prev; } -NORETURN __attribute__((naked)) void nlr_jump(void *val) { +NORETURN void nlr_jump(void *val) { nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); nlr_buf_t *top = *top_ptr; if (top == NULL) { @@ -138,7 +141,11 @@ NORETURN __attribute__((naked)) void nlr_jump(void *val) { : // clobbered registers ); + #if defined(__GNUC__) + __builtin_unreachable(); + #else for (;;); // needed to silence compiler warning + #endif } #endif // (!defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP) && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) From 5bf8e85fc828974199d469db711aa2f9649c467b Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 28 Dec 2017 16:18:39 +1100 Subject: [PATCH 222/828] py/nlr: Clean up selection and config of NLR implementation. If MICROPY_NLR_SETJMP is not enabled and the machine is auto-detected then nlr.h now defines some convenience macros for the individual NLR implementations to use (eg MICROPY_NLR_THUMB). This keeps nlr.h and the implementation in sync, and also makes the nlr_buf_t struct easier to read. --- py/nlr.h | 44 +++++++++++++++++++++++++++----------------- py/nlrthumb.c | 4 ++-- py/nlrx64.c | 4 ++-- py/nlrx86.c | 4 ++-- py/nlrxtensa.c | 4 ++-- 5 files changed, 35 insertions(+), 25 deletions(-) diff --git a/py/nlr.h b/py/nlr.h index 1235f14609..bd9fcc8847 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -30,29 +30,28 @@ // exception handling, basically a stack of setjmp/longjmp buffers #include -#include #include #include "py/mpconfig.h" -typedef struct _nlr_buf_t nlr_buf_t; -struct _nlr_buf_t { - // the entries here must all be machine word size - nlr_buf_t *prev; - void *ret_val; // always a concrete object (an exception instance) -#if !defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP +// If MICROPY_NLR_SETJMP is not enabled then auto-detect the machine arch +#if !MICROPY_NLR_SETJMP #if defined(__i386__) - void *regs[6]; + #define MICROPY_NLR_X86 (1) + #define MICROPY_NLR_NUM_REGS (6) #elif defined(__x86_64__) - #if defined(__CYGWIN__) - void *regs[12]; - #else - void *regs[8]; - #endif + #define MICROPY_NLR_X64 (1) + #if defined(__CYGWIN__) + #define MICROPY_NLR_NUM_REGS (12) + #else + #define MICROPY_NLR_NUM_REGS (8) + #endif #elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__) - void *regs[10]; + #define MICROPY_NLR_THUMB (1) + #define MICROPY_NLR_NUM_REGS (10) #elif defined(__xtensa__) - void *regs[10]; + #define MICROPY_NLR_XTENSA (1) + #define MICROPY_NLR_NUM_REGS (10) #else #define MICROPY_NLR_SETJMP (1) //#warning "No native NLR support for this arch, using setjmp implementation" @@ -60,9 +59,21 @@ struct _nlr_buf_t { #endif #if MICROPY_NLR_SETJMP - jmp_buf jmpbuf; +#include #endif +typedef struct _nlr_buf_t nlr_buf_t; +struct _nlr_buf_t { + // the entries here must all be machine word size + nlr_buf_t *prev; + void *ret_val; // always a concrete object (an exception instance) + + #if MICROPY_NLR_SETJMP + jmp_buf jmpbuf; + #else + void *regs[MICROPY_NLR_NUM_REGS]; + #endif + #if MICROPY_ENABLE_PYSTACK void *pystack; #endif @@ -123,7 +134,6 @@ NORETURN void nlr_jump_fail(void *val); /* #define nlr_push(val) \ printf("nlr_push: before: nlr_top=%p, val=%p\n", MP_STATE_THREAD(nlr_top), val),assert(MP_STATE_THREAD(nlr_top) != val),nlr_push(val) -#endif */ #endif diff --git a/py/nlrthumb.c b/py/nlrthumb.c index 18d31eb706..cc081e3ffb 100644 --- a/py/nlrthumb.c +++ b/py/nlrthumb.c @@ -26,7 +26,7 @@ #include "py/mpstate.h" -#if (!defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP) && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) +#if MICROPY_NLR_THUMB #undef nlr_push @@ -148,4 +148,4 @@ NORETURN void nlr_jump(void *val) { #endif } -#endif // (!defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP) && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) +#endif // MICROPY_NLR_THUMB diff --git a/py/nlrx64.c b/py/nlrx64.c index ddcd761665..927b215912 100644 --- a/py/nlrx64.c +++ b/py/nlrx64.c @@ -26,7 +26,7 @@ #include "py/mpstate.h" -#if !MICROPY_NLR_SETJMP && defined(__x86_64__) +#if MICROPY_NLR_X64 #undef nlr_push @@ -138,4 +138,4 @@ NORETURN void nlr_jump(void *val) { for (;;); // needed to silence compiler warning } -#endif // !MICROPY_NLR_SETJMP && defined(__x86_64__) +#endif // MICROPY_NLR_X64 diff --git a/py/nlrx86.c b/py/nlrx86.c index 3a27460eb6..0e03eef6fe 100644 --- a/py/nlrx86.c +++ b/py/nlrx86.c @@ -26,7 +26,7 @@ #include "py/mpstate.h" -#if !MICROPY_NLR_SETJMP && defined(__i386__) +#if MICROPY_NLR_X86 #undef nlr_push @@ -114,4 +114,4 @@ NORETURN void nlr_jump(void *val) { for (;;); // needed to silence compiler warning } -#endif // !MICROPY_NLR_SETJMP && defined(__i386__) +#endif // MICROPY_NLR_X86 diff --git a/py/nlrxtensa.c b/py/nlrxtensa.c index 5a969fc87c..73f14385d0 100644 --- a/py/nlrxtensa.c +++ b/py/nlrxtensa.c @@ -26,7 +26,7 @@ #include "py/mpstate.h" -#if !MICROPY_NLR_SETJMP && defined(__xtensa__) +#if MICROPY_NLR_XTENSA #undef nlr_push @@ -101,4 +101,4 @@ NORETURN void nlr_jump(void *val) { for (;;); // needed to silence compiler warning } -#endif // !MICROPY_NLR_SETJMP && defined(__xtensa__) +#endif // MICROPY_NLR_XTENSA From b25f92160b318a096c516c430afde5472a944c19 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 28 Dec 2017 16:46:30 +1100 Subject: [PATCH 223/828] py/nlr: Factor out common NLR code to macro and generic funcs in nlr.c. Each NLR implementation (Thumb, x86, x64, xtensa, setjmp) duplicates a lot of the NLR code, specifically that dealing with pushing and popping the NLR pointer to maintain the linked-list of NLR buffers. This patch factors all of that code out of the specific implementations into generic functions in nlr.c, along with a helper macro in nlr.h. This eliminates duplicated code. --- py/nlr.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ py/nlr.h | 27 +++++++++++++++----------- py/nlrsetjmp.c | 6 +++--- py/nlrthumb.c | 25 ++----------------------- py/nlrx64.c | 23 +---------------------- py/nlrx86.c | 23 +---------------------- py/nlrxtensa.c | 23 +---------------------- py/py.mk | 1 + 8 files changed, 76 insertions(+), 103 deletions(-) create mode 100644 py/nlr.c diff --git a/py/nlr.c b/py/nlr.c new file mode 100644 index 0000000000..52d56afb8a --- /dev/null +++ b/py/nlr.c @@ -0,0 +1,51 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpstate.h" + +#if !MICROPY_NLR_SETJMP +// When not using setjmp, nlr_push_tail is called from inline asm so needs special c +#if MICROPY_NLR_X86 && (defined(_WIN32) || defined(__CYGWIN__)) +// On these 32-bit platforms make sure nlr_push_tail doesn't have a leading undersco +unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail"); +#else +// LTO can't see inside inline asm functions so explicitly mark nlr_push_tail as use +__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); +#endif +#endif + +unsigned int nlr_push_tail(nlr_buf_t *nlr) { + nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); + nlr->prev = *top; + MP_NLR_SAVE_PYSTACK(nlr); + *top = nlr; + return 0; // normal return +} + +void nlr_pop(void) { + nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); + *top = (*top)->prev; +} diff --git a/py/nlr.h b/py/nlr.h index bd9fcc8847..e4dfa68963 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -88,24 +88,29 @@ struct _nlr_buf_t { #define MP_NLR_RESTORE_PYSTACK(nlr_buf) (void)nlr_buf #endif -#if MICROPY_NLR_SETJMP -#include "py/mpstate.h" +// Helper macro to use at the start of a specific nlr_jump implementation +#define MP_NLR_JUMP_HEAD(val, top) \ + nlr_buf_t **_top_ptr = &MP_STATE_THREAD(nlr_top); \ + nlr_buf_t *top = *_top_ptr; \ + if (top == NULL) { \ + nlr_jump_fail(val); \ + } \ + top->ret_val = val; \ + MP_NLR_RESTORE_PYSTACK(top); \ + *_top_ptr = top->prev; \ -NORETURN void nlr_setjmp_jump(void *val); +#if MICROPY_NLR_SETJMP // nlr_push() must be defined as a macro, because "The stack context will be // invalidated if the function which called setjmp() returns." -#define nlr_push(buf) ( \ - (buf)->prev = MP_STATE_THREAD(nlr_top), \ - MP_NLR_SAVE_PYSTACK(buf), \ - MP_STATE_THREAD(nlr_top) = (buf), \ - setjmp((buf)->jmpbuf)) -#define nlr_pop() { MP_STATE_THREAD(nlr_top) = MP_STATE_THREAD(nlr_top)->prev; } -#define nlr_jump(val) nlr_setjmp_jump(val) +// For this case it is safe to call nlr_push_tail() first. +#define nlr_push(buf) (nlr_push_tail(buf), setjmp((buf)->jmpbuf)) #else unsigned int nlr_push(nlr_buf_t *); +#endif + +unsigned int nlr_push_tail(nlr_buf_t *top); void nlr_pop(void); NORETURN void nlr_jump(void *val); -#endif // This must be implemented by a port. It's called by nlr_jump // if no nlr buf has been pushed. It must not return, but rather diff --git a/py/nlrsetjmp.c b/py/nlrsetjmp.c index 63376a5537..960dd86f52 100644 --- a/py/nlrsetjmp.c +++ b/py/nlrsetjmp.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2017 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,11 +24,11 @@ * THE SOFTWARE. */ -#include "py/nlr.h" +#include "py/mpstate.h" #if MICROPY_NLR_SETJMP -void nlr_setjmp_jump(void *val) { +void nlr_jump(void *val) { nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); nlr_buf_t *top = *top_ptr; if (top == NULL) { diff --git a/py/nlrthumb.c b/py/nlrthumb.c index cc081e3ffb..fb0a92236f 100644 --- a/py/nlrthumb.c +++ b/py/nlrthumb.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013-2016 Damien P. George + * Copyright (c) 2013-2017 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -82,29 +82,8 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { #endif } -__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - nlr->prev = *top; - MP_NLR_SAVE_PYSTACK(nlr); - *top = nlr; - return 0; // normal return -} - -void nlr_pop(void) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - *top = (*top)->prev; -} - NORETURN void nlr_jump(void *val) { - nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); - nlr_buf_t *top = *top_ptr; - if (top == NULL) { - nlr_jump_fail(val); - } - - top->ret_val = val; - MP_NLR_RESTORE_PYSTACK(top); - *top_ptr = top->prev; + MP_NLR_JUMP_HEAD(val, top) __asm volatile ( "mov r0, %0 \n" // r0 points to nlr_buf diff --git a/py/nlrx64.c b/py/nlrx64.c index 927b215912..663a457b70 100644 --- a/py/nlrx64.c +++ b/py/nlrx64.c @@ -88,29 +88,8 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; // needed to silence compiler warning } -__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - nlr->prev = *top; - MP_NLR_SAVE_PYSTACK(nlr); - *top = nlr; - return 0; // normal return -} - -void nlr_pop(void) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - *top = (*top)->prev; -} - NORETURN void nlr_jump(void *val) { - nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); - nlr_buf_t *top = *top_ptr; - if (top == NULL) { - nlr_jump_fail(val); - } - - top->ret_val = val; - MP_NLR_RESTORE_PYSTACK(top); - *top_ptr = top->prev; + MP_NLR_JUMP_HEAD(val, top) __asm volatile ( "movq %0, %%rcx \n" // %rcx points to nlr_buf diff --git a/py/nlrx86.c b/py/nlrx86.c index 0e03eef6fe..9490c4f42c 100644 --- a/py/nlrx86.c +++ b/py/nlrx86.c @@ -70,29 +70,8 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; // needed to silence compiler warning } -__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - nlr->prev = *top; - MP_NLR_SAVE_PYSTACK(nlr); - *top = nlr; - return 0; // normal return -} - -void nlr_pop(void) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - *top = (*top)->prev; -} - NORETURN void nlr_jump(void *val) { - nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); - nlr_buf_t *top = *top_ptr; - if (top == NULL) { - nlr_jump_fail(val); - } - - top->ret_val = val; - MP_NLR_RESTORE_PYSTACK(top); - *top_ptr = top->prev; + MP_NLR_JUMP_HEAD(val, top) __asm volatile ( "mov %0, %%edx \n" // %edx points to nlr_buf diff --git a/py/nlrxtensa.c b/py/nlrxtensa.c index 73f14385d0..cd3dee364c 100644 --- a/py/nlrxtensa.c +++ b/py/nlrxtensa.c @@ -55,29 +55,8 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; // needed to silence compiler warning } -__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - nlr->prev = *top; - MP_NLR_SAVE_PYSTACK(nlr); - *top = nlr; - return 0; // normal return -} - -void nlr_pop(void) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - *top = (*top)->prev; -} - NORETURN void nlr_jump(void *val) { - nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); - nlr_buf_t *top = *top_ptr; - if (top == NULL) { - nlr_jump_fail(val); - } - - top->ret_val = val; - MP_NLR_RESTORE_PYSTACK(top); - *top_ptr = top->prev; + MP_NLR_JUMP_HEAD(val, top) __asm volatile ( "mov.n a2, %0 \n" // a2 points to nlr_buf diff --git a/py/py.mk b/py/py.mk index 0b5d5f8c40..de82a971bc 100644 --- a/py/py.mk +++ b/py/py.mk @@ -103,6 +103,7 @@ endif # py object files PY_O_BASENAME = \ mpstate.o \ + nlr.o \ nlrx86.o \ nlrx64.o \ nlrthumb.o \ From dfe8980acfc678bfa3270bd17b7b3e45958a0a3a Mon Sep 17 00:00:00 2001 From: "Peter D. Gray" Date: Wed, 20 Dec 2017 10:39:30 -0500 Subject: [PATCH 224/828] stm32/spi: If MICROPY_HW_SPIn_MISO undefined, do not claim pin on init. This permits output-only SPI use. --- ports/stm32/spi.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c index cfd9c2667f..3cd470ccb4 100644 --- a/ports/stm32/spi.c +++ b/ports/stm32/spi.c @@ -243,8 +243,7 @@ STATIC void spi_set_params(SPI_HandleTypeDef *spi, uint32_t prescale, int32_t ba // TODO allow to take a list of pins to use void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { const pyb_spi_obj_t *self; - const pin_obj_t *pins[4]; - pins[0] = NULL; + const pin_obj_t *pins[4] = { NULL, NULL, NULL, NULL }; if (0) { #if defined(MICROPY_HW_SPI1_SCK) @@ -254,7 +253,9 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { pins[0] = &MICROPY_HW_SPI1_NSS; #endif pins[1] = &MICROPY_HW_SPI1_SCK; + #if defined(MICROPY_HW_SPI1_MISO) pins[2] = &MICROPY_HW_SPI1_MISO; + #endif pins[3] = &MICROPY_HW_SPI1_MOSI; // enable the SPI clock __SPI1_CLK_ENABLE(); @@ -266,7 +267,9 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { pins[0] = &MICROPY_HW_SPI2_NSS; #endif pins[1] = &MICROPY_HW_SPI2_SCK; + #if defined(MICROPY_HW_SPI2_MISO) pins[2] = &MICROPY_HW_SPI2_MISO; + #endif pins[3] = &MICROPY_HW_SPI2_MOSI; // enable the SPI clock __SPI2_CLK_ENABLE(); @@ -278,7 +281,9 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { pins[0] = &MICROPY_HW_SPI3_NSS; #endif pins[1] = &MICROPY_HW_SPI3_SCK; + #if defined(MICROPY_HW_SPI3_MISO) pins[2] = &MICROPY_HW_SPI3_MISO; + #endif pins[3] = &MICROPY_HW_SPI3_MOSI; // enable the SPI clock __SPI3_CLK_ENABLE(); @@ -290,7 +295,9 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { pins[0] = &MICROPY_HW_SPI4_NSS; #endif pins[1] = &MICROPY_HW_SPI4_SCK; + #if defined(MICROPY_HW_SPI4_MISO) pins[2] = &MICROPY_HW_SPI4_MISO; + #endif pins[3] = &MICROPY_HW_SPI4_MOSI; // enable the SPI clock __SPI4_CLK_ENABLE(); @@ -302,7 +309,9 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { pins[0] = &MICROPY_HW_SPI5_NSS; #endif pins[1] = &MICROPY_HW_SPI5_SCK; + #if defined(MICROPY_HW_SPI5_MISO) pins[2] = &MICROPY_HW_SPI5_MISO; + #endif pins[3] = &MICROPY_HW_SPI5_MOSI; // enable the SPI clock __SPI5_CLK_ENABLE(); @@ -314,7 +323,9 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { pins[0] = &MICROPY_HW_SPI6_NSS; #endif pins[1] = &MICROPY_HW_SPI6_SCK; + #if defined(MICROPY_HW_SPI6_MISO) pins[2] = &MICROPY_HW_SPI6_MISO; + #endif pins[3] = &MICROPY_HW_SPI6_MOSI; // enable the SPI clock __SPI6_CLK_ENABLE(); @@ -327,7 +338,10 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { // init the GPIO lines uint32_t mode = MP_HAL_PIN_MODE_ALT; uint32_t pull = spi->Init.CLKPolarity == SPI_POLARITY_LOW ? MP_HAL_PIN_PULL_DOWN : MP_HAL_PIN_PULL_UP; - for (uint i = (enable_nss_pin && pins[0] ? 0 : 1); i < 4; i++) { + for (uint i = (enable_nss_pin ? 0 : 1); i < 4; i++) { + if (pins[i] == NULL) { + continue; + } mp_hal_pin_config_alt(pins[i], mode, pull, AF_FN_SPI, (self - &pyb_spi_obj[0]) + 1); } From 1039c5e6998561c452cfc23a836eec374bef39bd Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 23 Dec 2017 23:04:02 +1100 Subject: [PATCH 225/828] py/parse: Split out rule name from rule struct into separate array. The rule name is only used for debugging, and this patch makes things a bit cleaner by completely separating out the rule name from the rest of the rule data. --- py/parse.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/py/parse.c b/py/parse.c index b80cc8fb1a..7fcdf2c432 100644 --- a/py/parse.c +++ b/py/parse.c @@ -61,9 +61,6 @@ typedef struct _rule_t { byte rule_id; byte act; -#ifdef USE_RULE_NAME - const char *rule_name; -#endif uint16_t arg[]; } rule_t; @@ -94,13 +91,8 @@ enum { #define tok(t) (RULE_ARG_TOK | MP_TOKEN_##t) #define rule(r) (RULE_ARG_RULE | RULE_##r) #define opt_rule(r) (RULE_ARG_OPT_RULE | RULE_##r) -#ifdef USE_RULE_NAME -#define DEF_RULE(rule, comp, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, #rule, { __VA_ARGS__ } }; -#define DEF_RULE_NC(rule, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, #rule, { __VA_ARGS__ } }; -#else #define DEF_RULE(rule, comp, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, { __VA_ARGS__ } }; #define DEF_RULE_NC(rule, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, { __VA_ARGS__ } }; -#endif #include "py/grammar.h" #undef or #undef and @@ -130,6 +122,23 @@ STATIC const rule_t *const rules[] = { #undef DEF_RULE_NC }; +#if USE_RULE_NAME +// Define an array of rule names corresponding to each rule +STATIC const char *const rule_name_table[] = { +#define DEF_RULE(rule, comp, kind, ...) #rule, +#define DEF_RULE_NC(rule, kind, ...) +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC + "", // RULE_const_object +#define DEF_RULE(rule, comp, kind, ...) +#define DEF_RULE_NC(rule, kind, ...) #rule, +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC +}; +#endif + typedef struct _rule_stack_t { size_t src_line : 8 * sizeof(size_t) - 8; // maximum bits storing source line number size_t rule_id : 8; // this must be large enough to fit largest rule number @@ -313,11 +322,11 @@ void mp_parse_node_print(mp_parse_node_t pn, size_t indent) { #endif } else { size_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); -#ifdef USE_RULE_NAME - printf("%s(%u) (n=%u)\n", rules[MP_PARSE_NODE_STRUCT_KIND(pns)]->rule_name, (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n); -#else + #if USE_RULE_NAME + printf("%s(%u) (n=%u)\n", rule_name_table[MP_PARSE_NODE_STRUCT_KIND(pns)], (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n); + #else printf("rule(%u) (n=%u)\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n); -#endif + #endif for (size_t i = 0; i < n; i++) { mp_parse_node_print(pns->nodes[i], indent + 2); } @@ -797,7 +806,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { for (int j = 0; j < parser.rule_stack_top; ++j) { printf(" "); } - printf("%s n=%d i=%d bt=%d\n", rule->rule_name, n, i, backtrack); + printf("%s n=%d i=%d bt=%d\n", rule_name_table[rule->rule_id], n, i, backtrack); */ switch (rule->act & RULE_ACT_KIND_MASK) { From 845511af257cd33f1397c5dd05b1c9198d2be96a Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 23 Dec 2017 23:36:08 +1100 Subject: [PATCH 226/828] py/parse: Break rule data into separate act and arg arrays. Instead of each rule being stored in ROM as a struct with rule_id, act and arg, the act and arg parts are now in separate arrays and the rule_id part is removed because it's not needed. This reduces code size, by roughly one byte per grammar rule, around 150 bytes. --- py/parse.c | 94 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 32 deletions(-) diff --git a/py/parse.c b/py/parse.c index 7fcdf2c432..bc2afb494d 100644 --- a/py/parse.c +++ b/py/parse.c @@ -61,7 +61,7 @@ typedef struct _rule_t { byte rule_id; byte act; - uint16_t arg[]; + const uint16_t *arg; } rule_t; enum { @@ -81,6 +81,8 @@ enum { #undef DEF_RULE_NC }; +// Define an array of actions corresponding to each rule +STATIC const uint8_t rule_act_table[] = { #define or(n) (RULE_ACT_OR | n) #define and(n) (RULE_ACT_AND | n) #define and_ident(n) (RULE_ACT_AND | n | RULE_ACT_ALLOW_IDENT) @@ -88,35 +90,55 @@ enum { #define one_or_more (RULE_ACT_LIST | 2) #define list (RULE_ACT_LIST | 1) #define list_with_end (RULE_ACT_LIST | 3) -#define tok(t) (RULE_ARG_TOK | MP_TOKEN_##t) -#define rule(r) (RULE_ARG_RULE | RULE_##r) -#define opt_rule(r) (RULE_ARG_OPT_RULE | RULE_##r) -#define DEF_RULE(rule, comp, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, { __VA_ARGS__ } }; -#define DEF_RULE_NC(rule, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, { __VA_ARGS__ } }; + +#define DEF_RULE(rule, comp, kind, ...) kind, +#define DEF_RULE_NC(rule, kind, ...) #include "py/grammar.h" -#undef or -#undef and -#undef list -#undef list_with_end -#undef tok -#undef rule -#undef opt_rule -#undef one_or_more #undef DEF_RULE #undef DEF_RULE_NC -STATIC const rule_t *const rules[] = { -// define rules with a compile function -#define DEF_RULE(rule, comp, kind, ...) &rule_##rule, + 0, // RULE_const_object + +#define DEF_RULE(rule, comp, kind, ...) +#define DEF_RULE_NC(rule, kind, ...) kind, +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC + +#undef or +#undef and +#undef and_ident +#undef and_blank +#undef one_or_more +#undef list +#undef list_with_end +}; + +// Define the argument data for each rule +#define tok(t) (RULE_ARG_TOK | MP_TOKEN_##t) +#define rule(r) (RULE_ARG_RULE | RULE_##r) +#define opt_rule(r) (RULE_ARG_OPT_RULE | RULE_##r) + +#define DEF_RULE(rule, comp, kind, ...) static const uint16_t const rule_arg_##rule[] = { __VA_ARGS__ }; +#define DEF_RULE_NC(rule, kind, ...) static const uint16_t const rule_arg_##rule[] = { __VA_ARGS__ }; +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC + +#undef tok +#undef rule +#undef opt_rule + +// Define an array of pointers to corresponding rule data +STATIC const uint16_t *const rule_arg_table[] = { +#define DEF_RULE(rule, comp, kind, ...) &rule_arg_##rule[0], #define DEF_RULE_NC(rule, kind, ...) #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC NULL, // RULE_const_object - -// define rules without a compile function #define DEF_RULE(rule, comp, kind, ...) -#define DEF_RULE_NC(rule, kind, ...) &rule_##rule, +#define DEF_RULE_NC(rule, kind, ...) &rule_arg_##rule[0], #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC @@ -139,6 +161,10 @@ STATIC const char *const rule_name_table[] = { }; #endif +#if (MICROPY_COMP_CONST_FOLDING && MICROPY_COMP_CONST) || !MICROPY_ENABLE_DOC_STRING +static const rule_t rule_pass_stmt = {RULE_pass_stmt, (RULE_ACT_AND | 1), &rule_arg_pass_stmt[0]}; +#endif + typedef struct _rule_stack_t { size_t src_line : 8 * sizeof(size_t) - 8; // maximum bits storing source line number size_t rule_id : 8; // this must be large enough to fit largest rule number @@ -214,7 +240,7 @@ STATIC void *parser_alloc(parser_t *parser, size_t num_bytes) { return ret; } -STATIC void push_rule(parser_t *parser, size_t src_line, const rule_t *rule, size_t arg_i) { +STATIC void push_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t arg_i) { if (parser->rule_stack_top >= parser->rule_stack_alloc) { rule_stack_t *rs = m_renew(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc + MICROPY_ALLOC_PARSE_RULE_INC); parser->rule_stack = rs; @@ -222,19 +248,21 @@ STATIC void push_rule(parser_t *parser, size_t src_line, const rule_t *rule, siz } rule_stack_t *rs = &parser->rule_stack[parser->rule_stack_top++]; rs->src_line = src_line; - rs->rule_id = rule->rule_id; + rs->rule_id = rule_id; rs->arg_i = arg_i; } STATIC void push_rule_from_arg(parser_t *parser, size_t arg) { assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE || (arg & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE); size_t rule_id = arg & RULE_ARG_ARG_MASK; - push_rule(parser, parser->lexer->tok_line, rules[rule_id], 0); + push_rule(parser, parser->lexer->tok_line, rule_id, 0); } -STATIC void pop_rule(parser_t *parser, const rule_t **rule, size_t *arg_i, size_t *src_line) { +STATIC void pop_rule(parser_t *parser, rule_t *rule, size_t *arg_i, size_t *src_line) { parser->rule_stack_top -= 1; - *rule = rules[parser->rule_stack[parser->rule_stack_top].rule_id]; + rule->rule_id = parser->rule_stack[parser->rule_stack_top].rule_id; + rule->act = rule_act_table[rule->rule_id]; + rule->arg = rule_arg_table[rule->rule_id]; *arg_i = parser->rule_stack[parser->rule_stack_top].arg_i; *src_line = parser->rule_stack[parser->rule_stack_top].src_line; } @@ -656,7 +684,7 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args if (qstr_str(id)[0] == '_') { pop_result(parser); // pop const(value) pop_result(parser); // pop id - push_result_rule(parser, 0, rules[RULE_pass_stmt], 0); // replace with "pass" + push_result_rule(parser, 0, &rule_pass_stmt, 0); // replace with "pass" return true; } @@ -782,7 +810,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { case MP_PARSE_EVAL_INPUT: top_level_rule = RULE_eval_input; break; default: top_level_rule = RULE_file_input; } - push_rule(&parser, lex->tok_line, rules[top_level_rule], 0); + push_rule(&parser, lex->tok_line, top_level_rule, 0); // parse! @@ -797,7 +825,9 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { break; } - pop_rule(&parser, &rule, &i, &rule_src_line); + rule_t rule_data; + pop_rule(&parser, &rule_data, &i, &rule_src_line); + rule = &rule_data; n = rule->act & RULE_ACT_ARG_MASK; /* @@ -827,7 +857,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { } else { assert(kind == RULE_ARG_RULE); if (i + 1 < n) { - push_rule(&parser, rule_src_line, rule, i + 1); // save this or-rule + push_rule(&parser, rule_src_line, rule->rule_id, i + 1); // save this or-rule } push_rule_from_arg(&parser, rule->arg[i]); // push child of or-rule goto next_rule; @@ -879,7 +909,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { } } } else { - push_rule(&parser, rule_src_line, rule, i + 1); // save this and-rule + push_rule(&parser, rule_src_line, rule->rule_id, i + 1); // save this and-rule push_rule_from_arg(&parser, rule->arg[i]); // push child of and-rule goto next_rule; } @@ -900,7 +930,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { // Pushing the "pass" rule here will overwrite any RULE_const_object // entry that was on the result stack, allowing the GC to reclaim // the memory from the const object when needed. - push_result_rule(&parser, rule_src_line, rules[RULE_pass_stmt], 0); + push_result_rule(&parser, rule_src_line, &rule_pass_stmt, 0); break; } } @@ -1009,7 +1039,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { } } else { assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE); - push_rule(&parser, rule_src_line, rule, i + 1); // save this list-rule + push_rule(&parser, rule_src_line, rule->rule_id, i + 1); // save this list-rule push_rule_from_arg(&parser, arg); // push child of list-rule goto next_rule; } From 815a8cd1ae3a0a451b0b0b687277093f3392cdab Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 23 Dec 2017 23:49:48 +1100 Subject: [PATCH 227/828] py/parse: Pass rule_id to push_result_rule, instead of passing rule_t*. Reduces code size by eliminating quite a few pointer dereferences. --- py/parse.c | 60 +++++++++++++++++++++++++----------------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/py/parse.c b/py/parse.c index bc2afb494d..fffa989531 100644 --- a/py/parse.c +++ b/py/parse.c @@ -161,10 +161,6 @@ STATIC const char *const rule_name_table[] = { }; #endif -#if (MICROPY_COMP_CONST_FOLDING && MICROPY_COMP_CONST) || !MICROPY_ENABLE_DOC_STRING -static const rule_t rule_pass_stmt = {RULE_pass_stmt, (RULE_ACT_AND | 1), &rule_arg_pass_stmt[0]}; -#endif - typedef struct _rule_stack_t { size_t src_line : 8 * sizeof(size_t) - 8; // maximum bits storing source line number size_t rule_id : 8; // this must be large enough to fit largest rule number @@ -491,12 +487,12 @@ STATIC const mp_rom_map_elem_t mp_constants_table[] = { STATIC MP_DEFINE_CONST_MAP(mp_constants_map, mp_constants_table); #endif -STATIC void push_result_rule(parser_t *parser, size_t src_line, const rule_t *rule, size_t num_args); +STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t num_args); #if MICROPY_COMP_CONST_FOLDING -STATIC bool fold_logical_constants(parser_t *parser, const rule_t *rule, size_t *num_args) { - if (rule->rule_id == RULE_or_test - || rule->rule_id == RULE_and_test) { +STATIC bool fold_logical_constants(parser_t *parser, uint8_t rule_id, size_t *num_args) { + if (rule_id == RULE_or_test + || rule_id == RULE_and_test) { // folding for binary logical ops: or and size_t copy_to = *num_args; for (size_t i = copy_to; i > 0;) { @@ -506,7 +502,7 @@ STATIC bool fold_logical_constants(parser_t *parser, const rule_t *rule, size_t // always need to keep the last value break; } - if (rule->rule_id == RULE_or_test) { + if (rule_id == RULE_or_test) { if (mp_parse_node_is_const_true(pn)) { // break; @@ -533,7 +529,7 @@ STATIC bool fold_logical_constants(parser_t *parser, const rule_t *rule, size_t // we did a complete folding if there's only 1 arg left return *num_args == 1; - } else if (rule->rule_id == RULE_not_test_2) { + } else if (rule_id == RULE_not_test_2) { // folding for unary logical op: not mp_parse_node_t pn = peek_result(parser, 0); if (mp_parse_node_is_const_false(pn)) { @@ -551,23 +547,23 @@ STATIC bool fold_logical_constants(parser_t *parser, const rule_t *rule, size_t return false; } -STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args) { +STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { // this code does folding of arbitrary integer expressions, eg 1 + 2 * 3 + 4 // it does not do partial folding, eg 1 + 2 + x -> 3 + x mp_obj_t arg0; - if (rule->rule_id == RULE_expr - || rule->rule_id == RULE_xor_expr - || rule->rule_id == RULE_and_expr) { + if (rule_id == RULE_expr + || rule_id == RULE_xor_expr + || rule_id == RULE_and_expr) { // folding for binary ops: | ^ & mp_parse_node_t pn = peek_result(parser, num_args - 1); if (!mp_parse_node_get_int_maybe(pn, &arg0)) { return false; } mp_binary_op_t op; - if (rule->rule_id == RULE_expr) { + if (rule_id == RULE_expr) { op = MP_BINARY_OP_OR; - } else if (rule->rule_id == RULE_xor_expr) { + } else if (rule_id == RULE_xor_expr) { op = MP_BINARY_OP_XOR; } else { op = MP_BINARY_OP_AND; @@ -580,9 +576,9 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args } arg0 = mp_binary_op(op, arg0, arg1); } - } else if (rule->rule_id == RULE_shift_expr - || rule->rule_id == RULE_arith_expr - || rule->rule_id == RULE_term) { + } else if (rule_id == RULE_shift_expr + || rule_id == RULE_arith_expr + || rule_id == RULE_term) { // folding for binary ops: << >> + - * / % // mp_parse_node_t pn = peek_result(parser, num_args - 1); if (!mp_parse_node_get_int_maybe(pn, &arg0)) { @@ -626,7 +622,7 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args } arg0 = mp_binary_op(op, arg0, arg1); } - } else if (rule->rule_id == RULE_factor_2) { + } else if (rule_id == RULE_factor_2) { // folding for unary ops: + - ~ mp_parse_node_t pn = peek_result(parser, 0); if (!mp_parse_node_get_int_maybe(pn, &arg0)) { @@ -645,7 +641,7 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args arg0 = mp_unary_op(op, arg0); #if MICROPY_COMP_CONST - } else if (rule->rule_id == RULE_expr_stmt) { + } else if (rule_id == RULE_expr_stmt) { mp_parse_node_t pn1 = peek_result(parser, 0); if (!MP_PARSE_NODE_IS_NULL(pn1) && !(MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_expr_stmt_augassign) @@ -684,7 +680,7 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args if (qstr_str(id)[0] == '_') { pop_result(parser); // pop const(value) pop_result(parser); // pop id - push_result_rule(parser, 0, &rule_pass_stmt, 0); // replace with "pass" + push_result_rule(parser, 0, RULE_pass_stmt, 0); // replace with "pass" return true; } @@ -700,7 +696,7 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args #endif #if MICROPY_COMP_MODULE_CONST - } else if (rule->rule_id == RULE_atom_expr_normal) { + } else if (rule_id == RULE_atom_expr_normal) { mp_parse_node_t pn0 = peek_result(parser, 1); mp_parse_node_t pn1 = peek_result(parser, 0); if (!(MP_PARSE_NODE_IS_ID(pn0) @@ -745,9 +741,9 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args } #endif -STATIC void push_result_rule(parser_t *parser, size_t src_line, const rule_t *rule, size_t num_args) { +STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t num_args) { // optimise away parenthesis around an expression if possible - if (rule->rule_id == RULE_atom_paren) { + if (rule_id == RULE_atom_paren) { // there should be just 1 arg for this rule mp_parse_node_t pn = peek_result(parser, 0); if (MP_PARSE_NODE_IS_NULL(pn)) { @@ -761,11 +757,11 @@ STATIC void push_result_rule(parser_t *parser, size_t src_line, const rule_t *ru } #if MICROPY_COMP_CONST_FOLDING - if (fold_logical_constants(parser, rule, &num_args)) { + if (fold_logical_constants(parser, rule_id, &num_args)) { // we folded this rule so return straight away return; } - if (fold_constants(parser, rule, num_args)) { + if (fold_constants(parser, rule_id, num_args)) { // we folded this rule so return straight away return; } @@ -773,7 +769,7 @@ STATIC void push_result_rule(parser_t *parser, size_t src_line, const rule_t *ru mp_parse_node_struct_t *pn = parser_alloc(parser, sizeof(mp_parse_node_struct_t) + sizeof(mp_parse_node_t) * num_args); pn->source_line = src_line; - pn->kind_num_nodes = (rule->rule_id & 0xff) | (num_args << 8); + pn->kind_num_nodes = (rule_id & 0xff) | (num_args << 8); for (size_t i = num_args; i > 0; i--) { pn->nodes[i - 1] = pop_result(parser); } @@ -930,7 +926,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { // Pushing the "pass" rule here will overwrite any RULE_const_object // entry that was on the result stack, allowing the GC to reclaim // the memory from the const object when needed. - push_result_rule(&parser, rule_src_line, &rule_pass_stmt, 0); + push_result_rule(&parser, rule_src_line, RULE_pass_stmt, 0); break; } } @@ -976,7 +972,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { i += 1; } - push_result_rule(&parser, rule_src_line, rule, i); + push_result_rule(&parser, rule_src_line, rule->rule_id, i); } break; } @@ -1058,12 +1054,12 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { // list matched single item if (had_trailing_sep) { // if there was a trailing separator, make a list of a single item - push_result_rule(&parser, rule_src_line, rule, i); + push_result_rule(&parser, rule_src_line, rule->rule_id, i); } else { // just leave single item on stack (ie don't wrap in a list) } } else { - push_result_rule(&parser, rule_src_line, rule, i); + push_result_rule(&parser, rule_src_line, rule->rule_id, i); } break; } From 66d8885d85bb591810b25e763c0921372ab74ef4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 23 Dec 2017 23:53:01 +1100 Subject: [PATCH 228/828] py/parse: Pass rule_id to push_result_token, instead of passing rule_t*. --- py/parse.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/py/parse.c b/py/parse.c index fffa989531..6244af432c 100644 --- a/py/parse.c +++ b/py/parse.c @@ -414,7 +414,7 @@ STATIC mp_parse_node_t mp_parse_node_new_small_int_checked(parser_t *parser, mp_ return mp_parse_node_new_small_int(val); } -STATIC void push_result_token(parser_t *parser, const rule_t *rule) { +STATIC void push_result_token(parser_t *parser, uint8_t rule_id) { mp_parse_node_t pn; mp_lexer_t *lex = parser->lexer; if (lex->tok_kind == MP_TOKEN_NAME) { @@ -422,7 +422,7 @@ STATIC void push_result_token(parser_t *parser, const rule_t *rule) { #if MICROPY_COMP_CONST // if name is a standalone identifier, look it up in the table of dynamic constants mp_map_elem_t *elem; - if (rule->rule_id == RULE_atom + if (rule_id == RULE_atom && (elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP)) != NULL) { if (MP_OBJ_IS_SMALL_INT(elem->value)) { pn = mp_parse_node_new_small_int_checked(parser, elem->value); @@ -433,7 +433,7 @@ STATIC void push_result_token(parser_t *parser, const rule_t *rule) { pn = mp_parse_node_new_leaf(MP_PARSE_NODE_ID, id); } #else - (void)rule; + (void)rule_id; pn = mp_parse_node_new_leaf(MP_PARSE_NODE_ID, id); #endif } else if (lex->tok_kind == MP_TOKEN_INTEGER) { @@ -846,7 +846,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { uint16_t kind = rule->arg[i] & RULE_ARG_KIND_MASK; if (kind == RULE_ARG_TOK) { if (lex->tok_kind == (rule->arg[i] & RULE_ARG_ARG_MASK)) { - push_result_token(&parser, rule); + push_result_token(&parser, rule->rule_id); mp_lexer_to_next(lex); goto next_rule; } @@ -890,7 +890,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { if (lex->tok_kind == tok_kind) { // matched token if (tok_kind == MP_TOKEN_NAME) { - push_result_token(&parser, rule); + push_result_token(&parser, rule->rule_id); } mp_lexer_to_next(lex); } else { @@ -1022,7 +1022,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { if (i & 1 & n) { // separators which are tokens are not pushed to result stack } else { - push_result_token(&parser, rule); + push_result_token(&parser, rule->rule_id); } mp_lexer_to_next(lex); // got element of list, so continue parsing list From c2c92ceefc86d7e5cdc358c4ea3226844391ae44 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 24 Dec 2017 00:01:02 +1100 Subject: [PATCH 229/828] py/parse: Remove rule_t struct because it's no longer needed. --- py/parse.c | 79 +++++++++++++++++++++++++----------------------------- 1 file changed, 36 insertions(+), 43 deletions(-) diff --git a/py/parse.c b/py/parse.c index 6244af432c..1af0e9c5f4 100644 --- a/py/parse.c +++ b/py/parse.c @@ -58,12 +58,6 @@ // (un)comment to use rule names; for debugging //#define USE_RULE_NAME (1) -typedef struct _rule_t { - byte rule_id; - byte act; - const uint16_t *arg; -} rule_t; - enum { // define rules with a compile function #define DEF_RULE(rule, comp, kind, ...) RULE_##rule, @@ -254,13 +248,12 @@ STATIC void push_rule_from_arg(parser_t *parser, size_t arg) { push_rule(parser, parser->lexer->tok_line, rule_id, 0); } -STATIC void pop_rule(parser_t *parser, rule_t *rule, size_t *arg_i, size_t *src_line) { +STATIC uint8_t pop_rule(parser_t *parser, size_t *arg_i, size_t *src_line) { parser->rule_stack_top -= 1; - rule->rule_id = parser->rule_stack[parser->rule_stack_top].rule_id; - rule->act = rule_act_table[rule->rule_id]; - rule->arg = rule_arg_table[rule->rule_id]; + uint8_t rule_id = parser->rule_stack[parser->rule_stack_top].rule_id; *arg_i = parser->rule_stack[parser->rule_stack_top].arg_i; *src_line = parser->rule_stack[parser->rule_stack_top].src_line; + return rule_id; } bool mp_parse_node_is_const_false(mp_parse_node_t pn) { @@ -810,10 +803,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { // parse! - size_t n, i; // state for the current rule - size_t rule_src_line; // source line for the first token matched by the current rule bool backtrack = false; - const rule_t *rule = NULL; for (;;) { next_rule: @@ -821,10 +811,13 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { break; } - rule_t rule_data; - pop_rule(&parser, &rule_data, &i, &rule_src_line); - rule = &rule_data; - n = rule->act & RULE_ACT_ARG_MASK; + // Pop the next rule to process it + size_t i; // state for the current rule + size_t rule_src_line; // source line for the first token matched by the current rule + uint8_t rule_id = pop_rule(&parser, &i, &rule_src_line); + uint8_t rule_act = rule_act_table[rule_id]; + const uint16_t *rule_arg = rule_arg_table[rule_id]; + size_t n = rule_act & RULE_ACT_ARG_MASK; /* // debugging @@ -832,10 +825,10 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { for (int j = 0; j < parser.rule_stack_top; ++j) { printf(" "); } - printf("%s n=%d i=%d bt=%d\n", rule_name_table[rule->rule_id], n, i, backtrack); + printf("%s n=%d i=%d bt=%d\n", rule_name_table[rule_id], n, i, backtrack); */ - switch (rule->act & RULE_ACT_KIND_MASK) { + switch (rule_act & RULE_ACT_KIND_MASK) { case RULE_ACT_OR: if (i > 0 && !backtrack) { goto next_rule; @@ -843,19 +836,19 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { backtrack = false; } for (; i < n; ++i) { - uint16_t kind = rule->arg[i] & RULE_ARG_KIND_MASK; + uint16_t kind = rule_arg[i] & RULE_ARG_KIND_MASK; if (kind == RULE_ARG_TOK) { - if (lex->tok_kind == (rule->arg[i] & RULE_ARG_ARG_MASK)) { - push_result_token(&parser, rule->rule_id); + if (lex->tok_kind == (rule_arg[i] & RULE_ARG_ARG_MASK)) { + push_result_token(&parser, rule_id); mp_lexer_to_next(lex); goto next_rule; } } else { assert(kind == RULE_ARG_RULE); if (i + 1 < n) { - push_rule(&parser, rule_src_line, rule->rule_id, i + 1); // save this or-rule + push_rule(&parser, rule_src_line, rule_id, i + 1); // save this or-rule } - push_rule_from_arg(&parser, rule->arg[i]); // push child of or-rule + push_rule_from_arg(&parser, rule_arg[i]); // push child of or-rule goto next_rule; } } @@ -867,7 +860,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { // failed, backtrack if we can, else syntax error if (backtrack) { assert(i > 0); - if ((rule->arg[i - 1] & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE) { + if ((rule_arg[i - 1] & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE) { // an optional rule that failed, so continue with next arg push_result_node(&parser, MP_PARSE_NODE_NULL); backtrack = false; @@ -884,13 +877,13 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { // progress through the rule for (; i < n; ++i) { - if ((rule->arg[i] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { + if ((rule_arg[i] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { // need to match a token - mp_token_kind_t tok_kind = rule->arg[i] & RULE_ARG_ARG_MASK; + mp_token_kind_t tok_kind = rule_arg[i] & RULE_ARG_ARG_MASK; if (lex->tok_kind == tok_kind) { // matched token if (tok_kind == MP_TOKEN_NAME) { - push_result_token(&parser, rule->rule_id); + push_result_token(&parser, rule_id); } mp_lexer_to_next(lex); } else { @@ -905,8 +898,8 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { } } } else { - push_rule(&parser, rule_src_line, rule->rule_id, i + 1); // save this and-rule - push_rule_from_arg(&parser, rule->arg[i]); // push child of and-rule + push_rule(&parser, rule_src_line, rule_id, i + 1); // save this and-rule + push_rule_from_arg(&parser, rule_arg[i]); // push child of and-rule goto next_rule; } } @@ -917,7 +910,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { #if !MICROPY_ENABLE_DOC_STRING // this code discards lonely statements, such as doc strings - if (input_kind != MP_PARSE_SINGLE_INPUT && rule->rule_id == RULE_expr_stmt && peek_result(&parser, 0) == MP_PARSE_NODE_NULL) { + if (input_kind != MP_PARSE_SINGLE_INPUT && rule_id == RULE_expr_stmt && peek_result(&parser, 0) == MP_PARSE_NODE_NULL) { mp_parse_node_t p = peek_result(&parser, 1); if ((MP_PARSE_NODE_IS_LEAF(p) && !MP_PARSE_NODE_IS_ID(p)) || MP_PARSE_NODE_IS_STRUCT_KIND(p, RULE_const_object)) { @@ -937,8 +930,8 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { size_t num_not_nil = 0; for (size_t x = n; x > 0;) { --x; - if ((rule->arg[x] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { - mp_token_kind_t tok_kind = rule->arg[x] & RULE_ARG_ARG_MASK; + if ((rule_arg[x] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { + mp_token_kind_t tok_kind = rule_arg[x] & RULE_ARG_ARG_MASK; if (tok_kind == MP_TOKEN_NAME) { // only tokens which were names are pushed to stack i += 1; @@ -953,7 +946,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { } } - if (num_not_nil == 1 && (rule->act & RULE_ACT_ALLOW_IDENT)) { + if (num_not_nil == 1 && (rule_act & RULE_ACT_ALLOW_IDENT)) { // this rule has only 1 argument and should not be emitted mp_parse_node_t pn = MP_PARSE_NODE_NULL; for (size_t x = 0; x < i; ++x) { @@ -966,19 +959,19 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { } else { // this rule must be emitted - if (rule->act & RULE_ACT_ADD_BLANK) { + if (rule_act & RULE_ACT_ADD_BLANK) { // and add an extra blank node at the end (used by the compiler to store data) push_result_node(&parser, MP_PARSE_NODE_NULL); i += 1; } - push_result_rule(&parser, rule_src_line, rule->rule_id, i); + push_result_rule(&parser, rule_src_line, rule_id, i); } break; } default: { - assert((rule->act & RULE_ACT_KIND_MASK) == RULE_ACT_LIST); + assert((rule_act & RULE_ACT_KIND_MASK) == RULE_ACT_LIST); // n=2 is: item item* // n=1 is: item (sep item)* @@ -1016,13 +1009,13 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { } } else { for (;;) { - size_t arg = rule->arg[i & 1 & n]; + size_t arg = rule_arg[i & 1 & n]; if ((arg & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { if (lex->tok_kind == (arg & RULE_ARG_ARG_MASK)) { if (i & 1 & n) { // separators which are tokens are not pushed to result stack } else { - push_result_token(&parser, rule->rule_id); + push_result_token(&parser, rule_id); } mp_lexer_to_next(lex); // got element of list, so continue parsing list @@ -1035,7 +1028,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { } } else { assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE); - push_rule(&parser, rule_src_line, rule->rule_id, i + 1); // save this list-rule + push_rule(&parser, rule_src_line, rule_id, i + 1); // save this list-rule push_rule_from_arg(&parser, arg); // push child of list-rule goto next_rule; } @@ -1045,7 +1038,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { // compute number of elements in list, result in i i -= 1; - if ((n & 1) && (rule->arg[1] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { + if ((n & 1) && (rule_arg[1] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { // don't count separators when they are tokens i = (i + 1) / 2; } @@ -1054,12 +1047,12 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { // list matched single item if (had_trailing_sep) { // if there was a trailing separator, make a list of a single item - push_result_rule(&parser, rule_src_line, rule->rule_id, i); + push_result_rule(&parser, rule_src_line, rule_id, i); } else { // just leave single item on stack (ie don't wrap in a list) } } else { - push_result_rule(&parser, rule_src_line, rule->rule_id, i); + push_result_rule(&parser, rule_src_line, rule_id, i); } break; } From 0016a45368d8e7272d1c1f891994d6de4effcb40 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 26 Dec 2017 13:39:02 +1100 Subject: [PATCH 230/828] py/parse: Compress rule pointer table to table of offsets. This is the sixth and final patch in a series of patches to the parser that aims to reduce code size by compressing the data corresponding to the rules of the grammar. Prior to this set of patches the rules were stored as rule_t structs with rule_id, act and arg members. And then there was a big table of pointers which allowed to lookup the address of a rule_t struct given the id of that rule. The changes that have been made are: - Breaking up of the rule_t struct into individual components, with each component in a separate array. - Removal of the rule_id part of the struct because it's not needed. - Put all the rule arg data in a big array. - Change the table of pointers to rules to a table of offsets within the array of rule arg data. The last point is what is done in this patch here and brings about the biggest decreases in code size, because an array of pointers is now an array of bytes. Code size changes for the six patches combined is: bare-arm: -644 minimal x86: -1856 unix x64: -5408 unix nanbox: -2080 stm32: -720 esp8266: -812 cc3200: -712 For the change in parser performance: it was measured on pyboard that these six patches combined gave an increase in script parse time of about 0.4%. This is due to the slightly more complicated way of looking up the data for a rule (since the 9th bit of the offset into the rule arg data table is calculated with an if statement). This is an acceptable increase in parse time considering that parsing is only done once per script (if compiled on the target). --- py/parse.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 10 deletions(-) diff --git a/py/parse.c b/py/parse.c index 1af0e9c5f4..8e07931850 100644 --- a/py/parse.c +++ b/py/parse.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013-2015 Damien P. George + * Copyright (c) 2013-2017 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -108,13 +108,20 @@ STATIC const uint8_t rule_act_table[] = { #undef list_with_end }; -// Define the argument data for each rule +// Define the argument data for each rule, as a combined array +STATIC const uint16_t rule_arg_combined_table[] = { #define tok(t) (RULE_ARG_TOK | MP_TOKEN_##t) #define rule(r) (RULE_ARG_RULE | RULE_##r) #define opt_rule(r) (RULE_ARG_OPT_RULE | RULE_##r) -#define DEF_RULE(rule, comp, kind, ...) static const uint16_t const rule_arg_##rule[] = { __VA_ARGS__ }; -#define DEF_RULE_NC(rule, kind, ...) static const uint16_t const rule_arg_##rule[] = { __VA_ARGS__ }; +#define DEF_RULE(rule, comp, kind, ...) __VA_ARGS__, +#define DEF_RULE_NC(rule, kind, ...) +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC + +#define DEF_RULE(rule, comp, kind, ...) +#define DEF_RULE_NC(rule, kind, ...) __VA_ARGS__, #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC @@ -122,22 +129,60 @@ STATIC const uint8_t rule_act_table[] = { #undef tok #undef rule #undef opt_rule +}; -// Define an array of pointers to corresponding rule data -STATIC const uint16_t *const rule_arg_table[] = { -#define DEF_RULE(rule, comp, kind, ...) &rule_arg_##rule[0], +// Macro to create a list of N-1 identifiers where N is the number of variable arguments to the macro +#define RULE_PADDING(rule, ...) RULE_PADDING2(rule, __VA_ARGS__, RULE_PADDING_IDS(rule)) +#define RULE_PADDING2(rule, ...) RULE_PADDING3(rule, __VA_ARGS__) +#define RULE_PADDING3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) __VA_ARGS__ +#define RULE_PADDING_IDS(r) PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r, + +// Use an enum to create constants that specify where in rule_arg_combined_table a given rule starts +enum { +#define DEF_RULE(rule, comp, kind, ...) RULE_ARG_OFFSET_##rule, RULE_PADDING(rule, __VA_ARGS__) #define DEF_RULE_NC(rule, kind, ...) #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC - NULL, // RULE_const_object #define DEF_RULE(rule, comp, kind, ...) -#define DEF_RULE_NC(rule, kind, ...) &rule_arg_##rule[0], +#define DEF_RULE_NC(rule, kind, ...) RULE_ARG_OFFSET_##rule, RULE_PADDING(rule, __VA_ARGS__) #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC }; +// Use the above enum values to create a table of offsets for each rule's arg +// data, which indexes rule_arg_combined_table. The offsets require 9 bits of +// storage but only the lower 8 bits are stored here. The 9th bit is computed +// in get_rule_arg using the FIRST_RULE_WITH_OFFSET_ABOVE_255 constant. +STATIC const uint8_t rule_arg_offset_table[] = { +#define DEF_RULE(rule, comp, kind, ...) RULE_ARG_OFFSET_##rule & 0xff, +#define DEF_RULE_NC(rule, kind, ...) +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC + 0, // RULE_const_object +#define DEF_RULE(rule, comp, kind, ...) +#define DEF_RULE_NC(rule, kind, ...) RULE_ARG_OFFSET_##rule & 0xff, +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC +}; + +// Define a constant that's used to determine the 9th bit of the values in rule_arg_offset_table +static const size_t FIRST_RULE_WITH_OFFSET_ABOVE_255 = +#define DEF_RULE(rule, comp, kind, ...) RULE_ARG_OFFSET_##rule >= 0x100 ? RULE_##rule : +#define DEF_RULE_NC(rule, kind, ...) +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC +#define DEF_RULE(rule, comp, kind, ...) +#define DEF_RULE_NC(rule, kind, ...) RULE_ARG_OFFSET_##rule >= 0x100 ? RULE_##rule : +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC +0; + #if USE_RULE_NAME // Define an array of rule names corresponding to each rule STATIC const char *const rule_name_table[] = { @@ -189,6 +234,14 @@ typedef struct _parser_t { #endif } parser_t; +STATIC const uint16_t *get_rule_arg(uint8_t r_id) { + size_t off = rule_arg_offset_table[r_id]; + if (r_id >= FIRST_RULE_WITH_OFFSET_ABOVE_255) { + off |= 0x100; + } + return &rule_arg_combined_table[off]; +} + STATIC void *parser_alloc(parser_t *parser, size_t num_bytes) { // use a custom memory allocator to store parse nodes sequentially in large chunks @@ -816,7 +869,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { size_t rule_src_line; // source line for the first token matched by the current rule uint8_t rule_id = pop_rule(&parser, &i, &rule_src_line); uint8_t rule_act = rule_act_table[rule_id]; - const uint16_t *rule_arg = rule_arg_table[rule_id]; + const uint16_t *rule_arg = get_rule_arg(rule_id); size_t n = rule_act & RULE_ACT_ARG_MASK; /* From d3fbfa491f46ec7e3f69d12e037cb3da7b3ae984 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 26 Dec 2017 13:39:26 +1100 Subject: [PATCH 231/828] py/parse: Update debugging code to compile on 64-bit arch. --- py/parse.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/py/parse.c b/py/parse.c index 8e07931850..238c946956 100644 --- a/py/parse.c +++ b/py/parse.c @@ -872,14 +872,14 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { const uint16_t *rule_arg = get_rule_arg(rule_id); size_t n = rule_act & RULE_ACT_ARG_MASK; - /* + #if 0 // debugging - printf("depth=%d ", parser.rule_stack_top); + printf("depth=" UINT_FMT " ", parser.rule_stack_top); for (int j = 0; j < parser.rule_stack_top; ++j) { printf(" "); } - printf("%s n=%d i=%d bt=%d\n", rule_name_table[rule_id], n, i, backtrack); - */ + printf("%s n=" UINT_FMT " i=" UINT_FMT " bt=%d\n", rule_name_table[rule_id], n, i, backtrack); + #endif switch (rule_act & RULE_ACT_KIND_MASK) { case RULE_ACT_OR: From c7cb1dfcb9f89eb0a2d2a90a5e496e919c8a0b94 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 29 Dec 2017 00:53:57 +1100 Subject: [PATCH 232/828] py/parse: Fix macro evaluation by avoiding empty __VA_ARGS__. Empty __VA_ARGS__ are not allowed in the C preprocessor so adjust the rule arg offset calculation to not use them. Also, some compilers (eg MSVC) require an extra layer of macro expansion. --- py/parse.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/py/parse.c b/py/parse.c index 238c946956..8c1286492f 100644 --- a/py/parse.c +++ b/py/parse.c @@ -131,39 +131,46 @@ STATIC const uint16_t rule_arg_combined_table[] = { #undef opt_rule }; -// Macro to create a list of N-1 identifiers where N is the number of variable arguments to the macro +// Macro to create a list of N identifiers where N is the number of variable arguments to the macro +#define RULE_EXPAND(x) x #define RULE_PADDING(rule, ...) RULE_PADDING2(rule, __VA_ARGS__, RULE_PADDING_IDS(rule)) -#define RULE_PADDING2(rule, ...) RULE_PADDING3(rule, __VA_ARGS__) -#define RULE_PADDING3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) __VA_ARGS__ +#define RULE_PADDING2(rule, ...) RULE_EXPAND(RULE_PADDING3(rule, __VA_ARGS__)) +#define RULE_PADDING3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) __VA_ARGS__ #define RULE_PADDING_IDS(r) PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r, -// Use an enum to create constants that specify where in rule_arg_combined_table a given rule starts +// Use an enum to create constants specifying how much room a rule takes in rule_arg_combined_table enum { -#define DEF_RULE(rule, comp, kind, ...) RULE_ARG_OFFSET_##rule, RULE_PADDING(rule, __VA_ARGS__) +#define DEF_RULE(rule, comp, kind, ...) RULE_PADDING(rule, __VA_ARGS__) #define DEF_RULE_NC(rule, kind, ...) #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC #define DEF_RULE(rule, comp, kind, ...) -#define DEF_RULE_NC(rule, kind, ...) RULE_ARG_OFFSET_##rule, RULE_PADDING(rule, __VA_ARGS__) +#define DEF_RULE_NC(rule, kind, ...) RULE_PADDING(rule, __VA_ARGS__) #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC }; +// Macro to compute the start of a rule in rule_arg_combined_table +#define RULE_ARG_OFFSET(rule, ...) RULE_ARG_OFFSET2(rule, __VA_ARGS__, RULE_ARG_OFFSET_IDS(rule)) +#define RULE_ARG_OFFSET2(rule, ...) RULE_EXPAND(RULE_ARG_OFFSET3(rule, __VA_ARGS__)) +#define RULE_ARG_OFFSET3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) _13 +#define RULE_ARG_OFFSET_IDS(r) PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r, PAD0_##r, + // Use the above enum values to create a table of offsets for each rule's arg // data, which indexes rule_arg_combined_table. The offsets require 9 bits of // storage but only the lower 8 bits are stored here. The 9th bit is computed // in get_rule_arg using the FIRST_RULE_WITH_OFFSET_ABOVE_255 constant. STATIC const uint8_t rule_arg_offset_table[] = { -#define DEF_RULE(rule, comp, kind, ...) RULE_ARG_OFFSET_##rule & 0xff, +#define DEF_RULE(rule, comp, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) & 0xff, #define DEF_RULE_NC(rule, kind, ...) #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC 0, // RULE_const_object #define DEF_RULE(rule, comp, kind, ...) -#define DEF_RULE_NC(rule, kind, ...) RULE_ARG_OFFSET_##rule & 0xff, +#define DEF_RULE_NC(rule, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) & 0xff, #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC @@ -171,13 +178,13 @@ STATIC const uint8_t rule_arg_offset_table[] = { // Define a constant that's used to determine the 9th bit of the values in rule_arg_offset_table static const size_t FIRST_RULE_WITH_OFFSET_ABOVE_255 = -#define DEF_RULE(rule, comp, kind, ...) RULE_ARG_OFFSET_##rule >= 0x100 ? RULE_##rule : +#define DEF_RULE(rule, comp, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) >= 0x100 ? RULE_##rule : #define DEF_RULE_NC(rule, kind, ...) #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC #define DEF_RULE(rule, comp, kind, ...) -#define DEF_RULE_NC(rule, kind, ...) RULE_ARG_OFFSET_##rule >= 0x100 ? RULE_##rule : +#define DEF_RULE_NC(rule, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) >= 0x100 ? RULE_##rule : #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC From 9766fddcdc29cb2b5a8657389b870703580a6e57 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 28 Dec 2017 14:02:36 +1100 Subject: [PATCH 233/828] py/mpz: Simplify handling of borrow and quo adjustment in mpn_div. The motivation behind this patch is to remove unreachable code in mpn_div. This unreachable code was added some time ago in 9a21d2e070c9ee0ef2c003f3a668e635c6ae4401, when a loop in mpn_div was copied and adjusted to work when mpz_dig_t was exactly half of the size of mpz_dbl_dig_t (a common case). The loop was copied correctly but it wasn't noticed at the time that the final part of the calculation of num-quo*den could be optimised, and hence unreachable code was left for a case that never occurred. The observation for the optimisation is that the initial value of quo in mpn_div is either exact or too large (never too small), and therefore the subtraction of quo*den from num may subtract exactly enough or too much (but never too little). Using this observation the part of the algorithm that handles the borrow value can be simplified, and most importantly this eliminates the unreachable code. The new code has been tested with DIG_SIZE=3 and DIG_SIZE=4 by dividing all possible combinations of non-negative integers with between 0 and 3 (inclusive) mpz digits. --- py/mpz.c | 114 +++++++++++++++++++++---------------------------------- py/mpz.h | 4 ++ 2 files changed, 48 insertions(+), 70 deletions(-) diff --git a/py/mpz.c b/py/mpz.c index 018a5454f8..78dee31325 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -537,83 +537,57 @@ STATIC void mpn_div(mpz_dig_t *num_dig, size_t *num_len, const mpz_dig_t *den_di // not to overflow the borrow variable. And the shifting of // borrow needs some special logic (it's a shift right with // round up). - - if (DIG_SIZE < 8 * sizeof(mpz_dbl_dig_t) / 2) { - const mpz_dig_t *d = den_dig; - mpz_dbl_dig_t d_norm = 0; - mpz_dbl_dig_signed_t borrow = 0; - - for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { - d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); - borrow += (mpz_dbl_dig_t)*n - (mpz_dbl_dig_t)quo * (d_norm & DIG_MASK); // will overflow if DIG_SIZE >= 8*sizeof(mpz_dbl_dig_t)/2 - *n = borrow & DIG_MASK; - borrow >>= DIG_SIZE; - } - borrow += *num_dig; // will overflow if DIG_SIZE >= 8*sizeof(mpz_dbl_dig_t)/2 - *num_dig = borrow & DIG_MASK; - borrow >>= DIG_SIZE; - - // adjust quotient if it is too big - for (; borrow != 0; --quo) { - d = den_dig; - d_norm = 0; - mpz_dbl_dig_t carry = 0; - for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { - d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); - carry += (mpz_dbl_dig_t)*n + (d_norm & DIG_MASK); - *n = carry & DIG_MASK; - carry >>= DIG_SIZE; - } - carry += *num_dig; - *num_dig = carry & DIG_MASK; - carry >>= DIG_SIZE; - - borrow += carry; - } - } else { // DIG_SIZE == 8 * sizeof(mpz_dbl_dig_t) / 2 - const mpz_dig_t *d = den_dig; - mpz_dbl_dig_t d_norm = 0; - mpz_dbl_dig_t borrow = 0; - - for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { - d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); - mpz_dbl_dig_t x = (mpz_dbl_dig_t)quo * (d_norm & DIG_MASK); - if (x >= *n || *n - x <= borrow) { - borrow += (mpz_dbl_dig_t)x - (mpz_dbl_dig_t)*n; - *n = (-borrow) & DIG_MASK; - borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up - } else { - *n = ((mpz_dbl_dig_t)*n - (mpz_dbl_dig_t)x - (mpz_dbl_dig_t)borrow) & DIG_MASK; - borrow = 0; - } - } - if (borrow >= *num_dig) { - borrow -= (mpz_dbl_dig_t)*num_dig; - *num_dig = (-borrow) & DIG_MASK; + // + const mpz_dig_t *d = den_dig; + mpz_dbl_dig_t d_norm = 0; + mpz_dbl_dig_t borrow = 0; + for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { + d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); + mpz_dbl_dig_t x = (mpz_dbl_dig_t)quo * (d_norm & DIG_MASK); + #if DIG_SIZE < MPZ_DBL_DIG_SIZE / 2 + borrow += (mpz_dbl_dig_t)*n - x; // will overflow if DIG_SIZE >= MPZ_DBL_DIG_SIZE/2 + *n = borrow & DIG_MASK; + borrow = (mpz_dbl_dig_signed_t)borrow >> DIG_SIZE; + #else // DIG_SIZE == MPZ_DBL_DIG_SIZE / 2 + if (x >= *n || *n - x <= borrow) { + borrow += x - (mpz_dbl_dig_t)*n; + *n = (-borrow) & DIG_MASK; borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up } else { - *num_dig = (*num_dig - borrow) & DIG_MASK; + *n = ((mpz_dbl_dig_t)*n - x - borrow) & DIG_MASK; borrow = 0; } + #endif + } - // adjust quotient if it is too big - for (; borrow != 0; --quo) { - d = den_dig; - d_norm = 0; - mpz_dbl_dig_t carry = 0; - for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { - d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); - carry += (mpz_dbl_dig_t)*n + (d_norm & DIG_MASK); - *n = carry & DIG_MASK; - carry >>= DIG_SIZE; - } - carry += (mpz_dbl_dig_t)*num_dig; - *num_dig = carry & DIG_MASK; + #if DIG_SIZE < MPZ_DBL_DIG_SIZE / 2 + // Borrow was negative in the above for-loop, make it positive for next if-block. + borrow = -borrow; + #endif + + // At this point we have either: + // + // 1. quo was the correct value and the most-sig-digit of num is exactly + // cancelled by borrow (borrow == *num_dig). In this case there is + // nothing more to do. + // + // 2. quo was too large, we subtracted too many den from num, and the + // most-sig-digit of num is 1 less than borrow (borrow == *num_dig + 1). + // In this case we must reduce quo and add back den to num until the + // carry from this operation cancels out the borrow. + // + borrow -= *num_dig; + for (; borrow != 0; --quo) { + d = den_dig; + d_norm = 0; + mpz_dbl_dig_t carry = 0; + for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { + d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); + carry += (mpz_dbl_dig_t)*n + (d_norm & DIG_MASK); + *n = carry & DIG_MASK; carry >>= DIG_SIZE; - - //assert(borrow >= carry); // enable this to check the logic - borrow -= carry; } + borrow -= carry; } // store this digit of the quotient diff --git a/py/mpz.h b/py/mpz.h index e2d0c30aac..3c36cac66b 100644 --- a/py/mpz.h +++ b/py/mpz.h @@ -55,18 +55,22 @@ #endif #if MPZ_DIG_SIZE > 16 +#define MPZ_DBL_DIG_SIZE (64) typedef uint32_t mpz_dig_t; typedef uint64_t mpz_dbl_dig_t; typedef int64_t mpz_dbl_dig_signed_t; #elif MPZ_DIG_SIZE > 8 +#define MPZ_DBL_DIG_SIZE (32) typedef uint16_t mpz_dig_t; typedef uint32_t mpz_dbl_dig_t; typedef int32_t mpz_dbl_dig_signed_t; #elif MPZ_DIG_SIZE > 4 +#define MPZ_DBL_DIG_SIZE (16) typedef uint8_t mpz_dig_t; typedef uint16_t mpz_dbl_dig_t; typedef int16_t mpz_dbl_dig_signed_t; #else +#define MPZ_DBL_DIG_SIZE (8) typedef uint8_t mpz_dig_t; typedef uint8_t mpz_dbl_dig_t; typedef int8_t mpz_dbl_dig_signed_t; From e78427443094163d1839387a2470fd22612ca8d1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 28 Dec 2017 14:14:06 +1100 Subject: [PATCH 234/828] py/mpz: In mpz_as_str_inpl, convert always-false checks to assertions. There are two checks that are always false so can be converted to (negated) assertions to save code space and execution time. They are: 1. The check of the str parameter, which is required to be non-NULL as per the original comment that it has enough space in it as calculated by mp_int_format_size. And for all uses of this function str is indeed non-NULL. 2. The check of the base parameter, which is already required to be between 2 and 16 (inclusive) via the assertion in mp_int_format_size. --- py/mpz.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/py/mpz.c b/py/mpz.c index 78dee31325..380e8968e6 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -1647,16 +1647,12 @@ char *mpz_as_str(const mpz_t *i, unsigned int base) { } #endif -// assumes enough space as calculated by mp_int_format_size +// assumes enough space in str as calculated by mp_int_format_size +// base must be between 2 and 32 inclusive // returns length of string, not including null byte size_t mpz_as_str_inpl(const mpz_t *i, unsigned int base, const char *prefix, char base_char, char comma, char *str) { - if (str == NULL) { - return 0; - } - if (base < 2 || base > 32) { - str[0] = 0; - return 0; - } + assert(str != NULL); + assert(2 <= base && base <= 32); size_t ilen = i->len; From 6fc58db5d8ea52e10b54b08e82fc2351d9f5caf0 Mon Sep 17 00:00:00 2001 From: stijn Date: Thu, 14 Dec 2017 10:58:49 +0100 Subject: [PATCH 235/828] windows/mpconfigport: Provide off_t definition for MSVC port For MSVC off_t is defined in sys/types.h but according to the comment earlier in mpconfigport.h this cannot be included directly. So just make off_t the same as mp_off_t. This fixes the build for MSVC with MICROPY_STREAMS_POSIX_API enabled because stream.h uses off_t. --- ports/windows/mpconfigport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/windows/mpconfigport.h b/ports/windows/mpconfigport.h index abad352825..e41f2ebbe0 100644 --- a/ports/windows/mpconfigport.h +++ b/ports/windows/mpconfigport.h @@ -232,6 +232,7 @@ typedef __int64 ssize_t; #define SSIZE_MAX _I32_MAX typedef int ssize_t; #endif +typedef mp_off_t off_t; // Put static/global variables in sections with a known name From 8041de59fed09e3185aaf01bb2faf1f733747dc8 Mon Sep 17 00:00:00 2001 From: stijn Date: Thu, 14 Dec 2017 11:09:59 +0100 Subject: [PATCH 236/828] windows/mpconfigport: Enable some features, including the Python stack Add some features which are already enabled in the unix port and default to using the Python stack for scoped allocations: this can be more performant in cases the heap is heavily used because for example the memory needed for storing *args and **kwargs doesn't require scanning the heap to find a free block. --- ports/windows/mpconfigport.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ports/windows/mpconfigport.h b/ports/windows/mpconfigport.h index e41f2ebbe0..1ae20fb04d 100644 --- a/ports/windows/mpconfigport.h +++ b/ports/windows/mpconfigport.h @@ -41,6 +41,7 @@ #define MICROPY_COMP_RETURN_IF_EXPR (1) #define MICROPY_ENABLE_GC (1) #define MICROPY_ENABLE_FINALISER (1) +#define MICROPY_ENABLE_PYSTACK (1) #define MICROPY_STACK_CHECK (1) #define MICROPY_MALLOC_USES_ALLOCATED_SIZE (1) #define MICROPY_MEM_STATS (1) @@ -56,6 +57,7 @@ #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_STREAMS_NON_BLOCK (1) +#define MICROPY_STREAMS_POSIX_API (1) #define MICROPY_OPT_COMPUTED_GOTO (0) #define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (1) #define MICROPY_CAN_OVERRIDE_BUILTINS (1) @@ -73,6 +75,7 @@ #define MICROPY_PY_BUILTINS_POW3 (1) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) #define MICROPY_PY_ALL_SPECIAL_METHODS (1) +#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) #define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) #define MICROPY_PY_SYS_EXIT (1) @@ -109,9 +112,12 @@ #define MICROPY_MACHINE_MEM_GET_WRITE_ADDR mod_machine_mem_get_addr #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED) +#define MICROPY_ERROR_PRINTER (&mp_stderr_print) #define MICROPY_WARNINGS (1) #define MICROPY_PY_STR_BYTES_CMP_WARN (1) +extern const struct _mp_print_t mp_stderr_print; + #ifdef _MSC_VER #define MICROPY_GCREGS_SETJMP (1) #endif From b184b6ae5334b87472897d0034a7388acafe41cc Mon Sep 17 00:00:00 2001 From: stijn Date: Tue, 26 Dec 2017 10:52:09 +0100 Subject: [PATCH 237/828] py/nlr: Fix nlr functions for 64bit ports built with gcc on Windows The number of registers used should be 10, not 12, to match the assembly code in nlrx64.c. With this change the 64bit mingw builds don't need to use the setjmp implementation, and this fixes miscellaneous crashes and assertion failures as reported in #1751 for instance. To avoid mistakes in the future where something gcc-related for Windows only gets fixed for one particular compiler/environment combination, make use of a MICROPY_NLR_OS_WINDOWS macro. To make sure everything nlr-related is now ok when built with gcc this has been verified with: - unix port built with gcc on Cygwin (i686-pc-cygwin-gcc and x86_64-pc-cygwin-gcc, version 6.4.0) - windows port built with mingw-w64's gcc from Cygwin (i686-w64-mingw32-gcc and x86_64-w64-mingw32-gcc, version 6.4.0) and MSYS2 (like the ones on Cygwin but version 7.2.0) --- ports/windows/Makefile | 4 ---- py/nlr.c | 2 +- py/nlr.h | 10 ++++++++-- py/nlrx64.c | 10 ++-------- py/nlrx86.c | 8 +------- 5 files changed, 12 insertions(+), 22 deletions(-) diff --git a/ports/windows/Makefile b/ports/windows/Makefile index b6433300fe..725cb686e5 100644 --- a/ports/windows/Makefile +++ b/ports/windows/Makefile @@ -50,10 +50,6 @@ CFLAGS_MOD += -DMICROPY_USE_READLINE=2 LDFLAGS_MOD += -lreadline endif -ifeq ($(CROSS_COMPILE),x86_64-w64-mingw32-) -CFLAGS_MOD += -DMICROPY_NLR_SETJMP=1 -endif - LIB += -lws2_32 # List of sources for qstr extraction diff --git a/py/nlr.c b/py/nlr.c index 52d56afb8a..7114d49978 100644 --- a/py/nlr.c +++ b/py/nlr.c @@ -28,7 +28,7 @@ #if !MICROPY_NLR_SETJMP // When not using setjmp, nlr_push_tail is called from inline asm so needs special c -#if MICROPY_NLR_X86 && (defined(_WIN32) || defined(__CYGWIN__)) +#if MICROPY_NLR_X86 && MICROPY_NLR_OS_WINDOWS // On these 32-bit platforms make sure nlr_push_tail doesn't have a leading undersco unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail"); #else diff --git a/py/nlr.h b/py/nlr.h index e4dfa68963..90595a12d3 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -36,13 +36,19 @@ // If MICROPY_NLR_SETJMP is not enabled then auto-detect the machine arch #if !MICROPY_NLR_SETJMP +// A lot of nlr-related things need different treatment on Windows +#if defined(_WIN32) || defined(__CYGWIN__) +#define MICROPY_NLR_OS_WINDOWS 1 +#else +#define MICROPY_NLR_OS_WINDOWS 0 +#endif #if defined(__i386__) #define MICROPY_NLR_X86 (1) #define MICROPY_NLR_NUM_REGS (6) #elif defined(__x86_64__) #define MICROPY_NLR_X64 (1) - #if defined(__CYGWIN__) - #define MICROPY_NLR_NUM_REGS (12) + #if MICROPY_NLR_OS_WINDOWS + #define MICROPY_NLR_NUM_REGS (10) #else #define MICROPY_NLR_NUM_REGS (8) #endif diff --git a/py/nlrx64.c b/py/nlrx64.c index 663a457b70..a3a1cf341b 100644 --- a/py/nlrx64.c +++ b/py/nlrx64.c @@ -33,18 +33,12 @@ // x86-64 callee-save registers are: // rbx, rbp, rsp, r12, r13, r14, r15 -#if defined(_WIN32) || defined(__CYGWIN__) -#define NLR_OS_WINDOWS 1 -#else -#define NLR_OS_WINDOWS 0 -#endif - __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); unsigned int nlr_push(nlr_buf_t *nlr) { (void)nlr; - #if NLR_OS_WINDOWS + #if MICROPY_NLR_OS_WINDOWS __asm volatile ( "movq (%rsp), %rax \n" // load return %rip @@ -93,7 +87,7 @@ NORETURN void nlr_jump(void *val) { __asm volatile ( "movq %0, %%rcx \n" // %rcx points to nlr_buf - #if NLR_OS_WINDOWS + #if MICROPY_NLR_OS_WINDOWS "movq 88(%%rcx), %%rsi \n" // load saved %rsi "movq 80(%%rcx), %%rdi \n" // load saved %rdr #endif diff --git a/py/nlrx86.c b/py/nlrx86.c index 9490c4f42c..23882cc307 100644 --- a/py/nlrx86.c +++ b/py/nlrx86.c @@ -33,13 +33,7 @@ // For reference, x86 callee save regs are: // ebx, esi, edi, ebp, esp, eip -#if defined(_WIN32) || defined(__CYGWIN__) -#define NLR_OS_WINDOWS 1 -#else -#define NLR_OS_WINDOWS 0 -#endif - -#if NLR_OS_WINDOWS +#if MICROPY_NLR_OS_WINDOWS unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail"); #else __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); From 42c4dd09a19ac864825786ece39d759bca34abd2 Mon Sep 17 00:00:00 2001 From: stijn Date: Thu, 28 Dec 2017 11:02:29 +0100 Subject: [PATCH 238/828] py/nlr: Fix missing trailing characters in comments in nlr.c --- py/nlr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/py/nlr.c b/py/nlr.c index 7114d49978..03d01577e1 100644 --- a/py/nlr.c +++ b/py/nlr.c @@ -27,12 +27,12 @@ #include "py/mpstate.h" #if !MICROPY_NLR_SETJMP -// When not using setjmp, nlr_push_tail is called from inline asm so needs special c +// When not using setjmp, nlr_push_tail is called from inline asm so needs special care #if MICROPY_NLR_X86 && MICROPY_NLR_OS_WINDOWS -// On these 32-bit platforms make sure nlr_push_tail doesn't have a leading undersco +// On these 32-bit platforms make sure nlr_push_tail doesn't have a leading underscore unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail"); #else -// LTO can't see inside inline asm functions so explicitly mark nlr_push_tail as use +// LTO can't see inside inline asm functions so explicitly mark nlr_push_tail as used __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); #endif #endif From bb3412291a0f88cb958852b268d5dc43db23d4fb Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 2 Jan 2018 21:36:46 +1100 Subject: [PATCH 239/828] drivers/display/ssd1306: Fix super() call in SSD1306 driver. --- drivers/display/ssd1306.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/display/ssd1306.py b/drivers/display/ssd1306.py index cebe10e677..178b4911d7 100644 --- a/drivers/display/ssd1306.py +++ b/drivers/display/ssd1306.py @@ -32,7 +32,7 @@ class SSD1306(framebuf.FrameBuffer): self.external_vcc = external_vcc self.pages = self.height // 8 self.buffer = bytearray(self.pages * self.width) - super.__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) + super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) self.init_display() def init_display(self): From a275cb0f487cd6517760271dc01d369c32600c63 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Tue, 19 Dec 2017 23:54:24 +0100 Subject: [PATCH 240/828] drivers/sdcard: Avoid allocation on the heap. This commit fixes two things: 1. Do not allocate on the heap in readblocks() - unless the block size is bigger than 512 bytes. 2. Raise an error instead of returning 1 to indicate an error: the FAT block device layer does not check the return value. And other backends (e.g. esp32 blockdev) also raise an error instead of returning non-zero. --- drivers/sdcard/sdcard.py | 48 ++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/drivers/sdcard/sdcard.py b/drivers/sdcard/sdcard.py index fedb76f02c..815631cae4 100644 --- a/drivers/sdcard/sdcard.py +++ b/drivers/sdcard/sdcard.py @@ -46,6 +46,7 @@ class SDCard: self.cmdbuf = bytearray(6) self.dummybuf = bytearray(512) + self.tokenbuf = bytearray(1) for i in range(512): self.dummybuf[i] = 0xff self.dummybuf_memoryview = memoryview(self.dummybuf) @@ -134,7 +135,7 @@ class SDCard: return raise OSError("timeout waiting for v2 card") - def cmd(self, cmd, arg, crc, final=0, release=True): + def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False): self.cs(0) # create and send the command @@ -147,9 +148,13 @@ class SDCard: buf[5] = crc self.spi.write(buf) + if skip1: + self.spi.readinto(self.tokenbuf, 0xff) + # wait for the response (response[7] == 0) for i in range(_CMD_TIMEOUT): - response = self.spi.read(1, 0xff)[0] + self.spi.readinto(self.tokenbuf, 0xff) + response = self.tokenbuf[0] if not (response & 0x80): # this could be a big-endian integer that we are getting here for j in range(final): @@ -164,27 +169,19 @@ class SDCard: self.spi.write(b'\xff') return -1 - def cmd_nodata(self, cmd): - self.spi.write(cmd) - self.spi.read(1, 0xff) # ignore stuff byte - for _ in range(_CMD_TIMEOUT): - if self.spi.read(1, 0xff)[0] == 0xff: - self.cs(1) - self.spi.write(b'\xff') - return 0 # OK - self.cs(1) - self.spi.write(b'\xff') - return 1 # timeout - def readinto(self, buf): self.cs(0) # read until start byte (0xff) - while self.spi.read(1, 0xff)[0] != 0xfe: - pass + while True: + self.spi.readinto(self.tokenbuf, 0xff) + if self.tokenbuf[0] == 0xfe: + break # read data - mv = self.dummybuf_memoryview[:len(buf)] + mv = self.dummybuf_memoryview + if len(buf) != len(mv): + mv = mv[:len(buf)] self.spi.write_readinto(mv, buf) # read checksum @@ -231,26 +228,26 @@ class SDCard: return self.sectors def readblocks(self, block_num, buf): - nblocks, err = divmod(len(buf), 512) - assert nblocks and not err, 'Buffer length is invalid' + nblocks = len(buf) // 512 + assert nblocks and not len(buf) % 512, 'Buffer length is invalid' if nblocks == 1: # CMD17: set read address for single block if self.cmd(17, block_num * self.cdv, 0) != 0: - return 1 + raise OSError(5) # EIO # receive the data self.readinto(buf) else: # CMD18: set read address for multiple blocks if self.cmd(18, block_num * self.cdv, 0) != 0: - return 1 + raise OSError(5) # EIO offset = 0 mv = memoryview(buf) while nblocks: self.readinto(mv[offset : offset + 512]) offset += 512 nblocks -= 1 - return self.cmd_nodata(b'\x0c') # cmd 12 - return 0 + if self.cmd(12, 0, 0xff, skip1=True): + raise OSError(5) # EIO def writeblocks(self, block_num, buf): nblocks, err = divmod(len(buf), 512) @@ -258,14 +255,14 @@ class SDCard: if nblocks == 1: # CMD24: set write address for single block if self.cmd(24, block_num * self.cdv, 0) != 0: - return 1 + raise OSError(5) # EIO # send the data self.write(_TOKEN_DATA, buf) else: # CMD25: set write address for first block if self.cmd(25, block_num * self.cdv, 0) != 0: - return 1 + raise OSError(5) # EIO # send the data offset = 0 mv = memoryview(buf) @@ -274,4 +271,3 @@ class SDCard: offset += 512 nblocks -= 1 self.write_token(_TOKEN_STOP_TRAN) - return 0 From 1ed2c23efb3dc4d12f07e10e20f6194da4babf16 Mon Sep 17 00:00:00 2001 From: "Peter D. Gray" Date: Thu, 4 Jan 2018 11:45:36 -0500 Subject: [PATCH 241/828] stm32/modmachine: Handle case of no MICROPY_PY_MACHINE_I2C. --- ports/stm32/modmachine.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index 8c59758fa3..d9eb6383e7 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -558,7 +558,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) }, { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) }, #endif +#if MICROPY_PY_MACHINE_I2C { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, +#endif { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_hard_spi_type) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) }, { MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&pyb_wdt_type) }, From df952633ef806d848ea75148a7be52e6a4e7f9fe Mon Sep 17 00:00:00 2001 From: stijn Date: Wed, 3 Jan 2018 21:10:03 +0100 Subject: [PATCH 242/828] windows: Add Appveyor CI builds for windows mingw port Build and test 32bit and 64bit versions of the windows port using gcc from mingw-w64. Note a bunch of tests which rely on floating point math/printing have been disabled for now since they fail. --- ports/windows/.appveyor.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ports/windows/.appveyor.yml b/ports/windows/.appveyor.yml index a82cf5adc9..795330eff0 100644 --- a/ports/windows/.appveyor.yml +++ b/ports/windows/.appveyor.yml @@ -24,6 +24,26 @@ test_script: %MICROPY_CPYTHON3% run-tests +# After the build/test phase for the MSVC build completes, +# build and test with mingw-w64, release versions only. +after_test: +- ps: | + if ($env:configuration -eq 'Debug') { + return + } + $env:MSYSTEM = if ($platform -eq 'x86') {'MINGW32'} else {'MINGW64'} + $env:CHERE_INVOKING = 'enabled_from_arguments' + cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'ports/windows') + C:\msys64\usr\bin\bash.exe -l -c "make -B -j4 V=1" + if ($LASTEXITCODE -ne 0) { + throw "$env:MSYSTEM build exited with code $LASTEXITCODE" + } + cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'tests') + & $env:MICROPY_CPYTHON3 run-tests -e math_fun -e float2int_double -e float_parse -e math_domain_special + if ($LASTEXITCODE -ne 0) { + throw "$env:MSYSTEM tests exited with code $LASTEXITCODE" + } + skip_tags: true deploy: off From 7642785881550bd71815623c4f93e0516217429c Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Tue, 19 Dec 2017 23:47:07 +0100 Subject: [PATCH 243/828] extmod/vfs_fat_file: Implement SEEK_CUR for non-zero offset. CPython doesn't allow SEEK_CUR with non-zero offset for files in text mode, and uPy inherited this behaviour for both text and binary files. It makes sense to provide full support for SEEK_CUR of binary-mode files in uPy, and to do this in a minimal way means also allowing to use SEEK_CUR with non-zero offsets on text-mode files. That seems to be a fair compromise. --- extmod/vfs_fat_file.c | 6 +----- tests/extmod/vfs_fat_fileio1.py | 6 ++---- tests/extmod/vfs_fat_fileio1.py.exp | 2 +- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c index 1fcbb253dc..6154c8483f 100644 --- a/extmod/vfs_fat_file.c +++ b/extmod/vfs_fat_file.c @@ -134,11 +134,7 @@ STATIC mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, break; case 1: // SEEK_CUR - if (s->offset != 0) { - *errcode = MP_EOPNOTSUPP; - return MP_STREAM_ERROR; - } - // no-operation + f_lseek(&self->fp, f_tell(&self->fp) + s->offset); break; case 2: // SEEK_END diff --git a/tests/extmod/vfs_fat_fileio1.py b/tests/extmod/vfs_fat_fileio1.py index d19df120b5..8b9ff92eb8 100644 --- a/tests/extmod/vfs_fat_fileio1.py +++ b/tests/extmod/vfs_fat_fileio1.py @@ -91,10 +91,8 @@ with open("foo_file.txt") as f2: f2.seek(0, 1) # SEEK_CUR print(f2.read(1)) - try: - f2.seek(1, 1) # SEEK_END - except OSError as e: - print(e.args[0] == uerrno.EOPNOTSUPP) + f2.seek(2, 1) # SEEK_CUR + print(f2.read(1)) f2.seek(-2, 2) # SEEK_END print(f2.read(1)) diff --git a/tests/extmod/vfs_fat_fileio1.py.exp b/tests/extmod/vfs_fat_fileio1.py.exp index d777585cf7..a66f07605c 100644 --- a/tests/extmod/vfs_fat_fileio1.py.exp +++ b/tests/extmod/vfs_fat_fileio1.py.exp @@ -7,7 +7,7 @@ hello!world! 12 h e -True +o d True [('foo_dir', 16384, 0)] From a40ce1d829eca6fe0fad0b7f4478a6651903dd2a Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 31 Jan 2018 18:11:06 +1100 Subject: [PATCH 244/828] esp8266/modules: Move dht.py driver to drivers/dht directory. --- drivers/dht/dht.py | 32 ++++++++++++++++++++++++++++++++ ports/esp32/modules/dht.py | 2 +- ports/esp8266/modules/dht.py | 33 +-------------------------------- 3 files changed, 34 insertions(+), 33 deletions(-) create mode 100644 drivers/dht/dht.py mode change 100644 => 120000 ports/esp8266/modules/dht.py diff --git a/drivers/dht/dht.py b/drivers/dht/dht.py new file mode 100644 index 0000000000..9a69e7e07e --- /dev/null +++ b/drivers/dht/dht.py @@ -0,0 +1,32 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import esp + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + esp.dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xff != buf[4]: + raise Exception("checksum error") + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7f) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/ports/esp32/modules/dht.py b/ports/esp32/modules/dht.py index b6acf2853e..2aa2f5cbfe 120000 --- a/ports/esp32/modules/dht.py +++ b/ports/esp32/modules/dht.py @@ -1 +1 @@ -../../esp8266/modules/dht.py \ No newline at end of file +../../../drivers/dht/dht.py \ No newline at end of file diff --git a/ports/esp8266/modules/dht.py b/ports/esp8266/modules/dht.py deleted file mode 100644 index 9a69e7e07e..0000000000 --- a/ports/esp8266/modules/dht.py +++ /dev/null @@ -1,32 +0,0 @@ -# DHT11/DHT22 driver for MicroPython on ESP8266 -# MIT license; Copyright (c) 2016 Damien P. George - -import esp - -class DHTBase: - def __init__(self, pin): - self.pin = pin - self.buf = bytearray(5) - - def measure(self): - buf = self.buf - esp.dht_readinto(self.pin, buf) - if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xff != buf[4]: - raise Exception("checksum error") - -class DHT11(DHTBase): - def humidity(self): - return self.buf[0] - - def temperature(self): - return self.buf[2] - -class DHT22(DHTBase): - def humidity(self): - return (self.buf[0] << 8 | self.buf[1]) * 0.1 - - def temperature(self): - t = ((self.buf[2] & 0x7f) << 8 | self.buf[3]) * 0.1 - if self.buf[2] & 0x80: - t = -t - return t diff --git a/ports/esp8266/modules/dht.py b/ports/esp8266/modules/dht.py new file mode 120000 index 0000000000..2aa2f5cbfe --- /dev/null +++ b/ports/esp8266/modules/dht.py @@ -0,0 +1 @@ +../../../drivers/dht/dht.py \ No newline at end of file From efdda2c62deba4f4f24672e441cffe496158bb35 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 31 Jan 2018 18:12:53 +1100 Subject: [PATCH 245/828] stm32: Add support for DHT11/DHT22 sensors. --- drivers/dht/dht.py | 7 +++++-- ports/stm32/Makefile | 1 + ports/stm32/modpyb.c | 4 ++++ ports/stm32/modules/dht.py | 1 + 4 files changed, 11 insertions(+), 2 deletions(-) create mode 120000 ports/stm32/modules/dht.py diff --git a/drivers/dht/dht.py b/drivers/dht/dht.py index 9a69e7e07e..eed61df7c9 100644 --- a/drivers/dht/dht.py +++ b/drivers/dht/dht.py @@ -1,7 +1,10 @@ # DHT11/DHT22 driver for MicroPython on ESP8266 # MIT license; Copyright (c) 2016 Damien P. George -import esp +try: + from esp import dht_readinto +except: + from pyb import dht_readinto class DHTBase: def __init__(self, pin): @@ -10,7 +13,7 @@ class DHTBase: def measure(self): buf = self.buf - esp.dht_readinto(self.pin, buf) + dht_readinto(self.pin, buf) if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xff != buf[4]: raise Exception("checksum error") diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 68b007471e..65962bea67 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -186,6 +186,7 @@ EXTMOD_SRC_C = $(addprefix extmod/,\ DRIVERS_SRC_C = $(addprefix drivers/,\ memory/spiflash.c \ + dht/dht.c \ ) SRC_C = \ diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c index 4d186e2787..970b5b954e 100644 --- a/ports/stm32/modpyb.c +++ b/ports/stm32/modpyb.c @@ -34,6 +34,7 @@ #include "lib/utils/pyexec.h" #include "lib/oofatfs/ff.h" #include "lib/oofatfs/diskio.h" +#include "drivers/dht/dht.h" #include "gccollect.h" #include "stm32_it.h" #include "irq.h" @@ -168,6 +169,9 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&mod_os_sync_obj) }, { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, + // This function is not intended to be public and may be moved elsewhere + { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&pyb_timer_type) }, #if MICROPY_HW_ENABLE_RNG diff --git a/ports/stm32/modules/dht.py b/ports/stm32/modules/dht.py new file mode 120000 index 0000000000..2aa2f5cbfe --- /dev/null +++ b/ports/stm32/modules/dht.py @@ -0,0 +1 @@ +../../../drivers/dht/dht.py \ No newline at end of file From 925c5b1da2fed80774dd393d597392a2c254effa Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 31 Jan 2018 18:21:07 +1100 Subject: [PATCH 246/828] lib/utils/pyexec.h: Include py/obj.h because its decls are needed. --- lib/utils/pyexec.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/utils/pyexec.h b/lib/utils/pyexec.h index bc98ba94a7..678c56cf48 100644 --- a/lib/utils/pyexec.h +++ b/lib/utils/pyexec.h @@ -26,6 +26,8 @@ #ifndef MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H #define MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H +#include "py/obj.h" + typedef enum { PYEXEC_MODE_RAW_REPL, PYEXEC_MODE_FRIENDLY_REPL, From bd257a838f605d4f45eb11edf9f89aa603ef2f33 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 31 Jan 2018 18:55:35 +1100 Subject: [PATCH 247/828] .gitmodules: Use https URL for lwIP submodule. HTTPS is supported by Savannah and better to be secure than not. --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index d2d8dd2783..c3f4c55aca 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,7 +7,7 @@ url = https://github.com/atgreen/libffi [submodule "lib/lwip"] path = lib/lwip - url = http://git.savannah.gnu.org/r/lwip.git + url = https://git.savannah.gnu.org/r/lwip.git [submodule "lib/berkeley-db-1.xx"] path = lib/berkeley-db-1.xx url = https://github.com/pfalcon/berkeley-db-1.xx From 23f9f9495f0b64e70470b17ba38cf1f2148724bd Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 31 Jan 2018 19:38:32 +1100 Subject: [PATCH 248/828] esp32/machine_uart: Fix check of UART id so it only allows valid UARTs. --- ports/esp32/machine_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp32/machine_uart.c b/ports/esp32/machine_uart.c index 0b303d424d..06d9c0b0da 100644 --- a/ports/esp32/machine_uart.c +++ b/ports/esp32/machine_uart.c @@ -187,7 +187,7 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, // get uart id mp_int_t uart_num = mp_obj_get_int(args[0]); - if (uart_num < 0 || uart_num > UART_NUM_MAX) { + if (uart_num < 0 || uart_num >= UART_NUM_MAX) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) does not exist", uart_num)); } From 524ff3027525832c85bf5411a6302578836b941a Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 31 Jan 2018 21:05:21 +1100 Subject: [PATCH 249/828] minimal/README: Update text to better describe what "make run" does. --- ports/minimal/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/minimal/README.md b/ports/minimal/README.md index 14b8c00a30..356fc4b3ef 100644 --- a/ports/minimal/README.md +++ b/ports/minimal/README.md @@ -9,7 +9,7 @@ By default the port will be built for the host machine: $ make -To run a small test script do: +To run the executable and get a basic working REPL do: $ make run From a44892dd0d79e039b4a4d1ec3ec7b9a6ed829ee6 Mon Sep 17 00:00:00 2001 From: Hemanth kumar Date: Wed, 17 Jan 2018 01:46:25 +0530 Subject: [PATCH 250/828] drivers/sdcard: Update doc for ESP8266 to use correct SPI number. machine.SPI(0) results in ValueError on ESP8266. SPI(1) is the user hardware SPI port (or use SPI(-1) for software SPI). --- drivers/sdcard/sdcard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sdcard/sdcard.py b/drivers/sdcard/sdcard.py index 815631cae4..719eb982e2 100644 --- a/drivers/sdcard/sdcard.py +++ b/drivers/sdcard/sdcard.py @@ -14,7 +14,7 @@ Example usage on pyboard: Example usage on ESP8266: import machine, sdcard, os - sd = sdcard.SDCard(machine.SPI(0), machine.Pin(15)) + sd = sdcard.SDCard(machine.SPI(1), machine.Pin(15)) os.umount() os.VfsFat(sd, "") os.listdir() From c0496fd44de562cd11e66acd9e42f796c3dcb5fb Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Feb 2018 11:45:29 +1100 Subject: [PATCH 251/828] stm32/spi: Make SPI DMA wait routine more power efficient by using WFI. The routine waits for the DMA to finish, which is signalled from a DMA IRQ handler. Using WFI makes the CPU sleep while waiting for the IRQ to arrive which decreases power consumption. To make it work correctly the check for the change in state must be atomic and so IRQs must be disabled during the check. The key feature of the Cortex MCU that makes this possible is that WFI will exit when an IRQ arrives even if IRQs are disabled. --- ports/stm32/spi.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c index 3cd470ccb4..2b5bdb038b 100644 --- a/ports/stm32/spi.c +++ b/ports/stm32/spi.c @@ -404,11 +404,16 @@ void spi_deinit(SPI_HandleTypeDef *spi) { } STATIC HAL_StatusTypeDef spi_wait_dma_finished(SPI_HandleTypeDef *spi, uint32_t timeout) { - // Note: we can't use WFI to idle in this loop because the DMA completion - // interrupt may occur before the WFI. Hence we miss it and have to wait - // until the next sys-tick (up to 1ms). uint32_t start = HAL_GetTick(); - while (HAL_SPI_GetState(spi) != HAL_SPI_STATE_READY) { + for (;;) { + // Do an atomic check of the state; WFI will exit even if IRQs are disabled + uint32_t irq_state = disable_irq(); + if (spi->State == HAL_SPI_STATE_READY) { + enable_irq(irq_state); + return HAL_OK; + } + __WFI(); + enable_irq(irq_state); if (HAL_GetTick() - start >= timeout) { return HAL_TIMEOUT; } From fed1b4fb56421e8f8a1ee54b2c16296204176bb3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Feb 2018 12:20:45 +1100 Subject: [PATCH 252/828] stm32/sdcard: Make SD wait routine more power efficient by using WFI. Using WFI allows the CPU to sleep while it is waiting, reducing power consumption. --- ports/stm32/sdcard.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index a54e05011c..46f08f78f6 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -244,11 +244,20 @@ void SDMMC2_IRQHandler(void) { STATIC HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd, uint32_t timeout) { // Wait for HAL driver to be ready (eg for DMA to finish) uint32_t start = HAL_GetTick(); - while (sd->State == HAL_SD_STATE_BUSY) { + for (;;) { + // Do an atomic check of the state; WFI will exit even if IRQs are disabled + uint32_t irq_state = disable_irq(); + if (sd->State != HAL_SD_STATE_BUSY) { + enable_irq(irq_state); + break; + } + __WFI(); + enable_irq(irq_state); if (HAL_GetTick() - start >= timeout) { return HAL_TIMEOUT; } } + // Wait for SD card to complete the operation for (;;) { HAL_SD_CardStateTypedef state = HAL_SD_GetCardState(sd); @@ -261,6 +270,7 @@ STATIC HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd, uint32_t tim if (HAL_GetTick() - start >= timeout) { return HAL_TIMEOUT; } + __WFI(); } return HAL_OK; } From 1d4246a2e8caa52f8381f405bfb37ba24b4246e7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Feb 2018 12:44:16 +1100 Subject: [PATCH 253/828] stm32/usbdev: Reduce dependency on py header files. --- ports/stm32/usbd_conf.h | 2 -- ports/stm32/usbd_desc.c | 3 +-- ports/stm32/usbd_msc_storage.c | 2 +- ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h | 4 ++-- ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 1 + 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/ports/stm32/usbd_conf.h b/ports/stm32/usbd_conf.h index 34ebe27b9a..b066bb2b81 100644 --- a/ports/stm32/usbd_conf.h +++ b/ports/stm32/usbd_conf.h @@ -38,8 +38,6 @@ #include #include -#include "py/mpconfig.h" - /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ /* Common Config */ diff --git a/ports/stm32/usbd_desc.c b/ports/stm32/usbd_desc.c index 1de75aee0f..0c7b2dfe5a 100644 --- a/ports/stm32/usbd_desc.c +++ b/ports/stm32/usbd_desc.c @@ -33,8 +33,7 @@ #include "usbd_desc.h" #include "usbd_conf.h" -// need these headers just for MP_HAL_UNIQUE_ID_ADDRESS -#include "py/misc.h" +// need this header just for MP_HAL_UNIQUE_ID_ADDRESS #include "py/mphal.h" // So we don't clash with existing ST boards, we use the unofficial FOSS VID. diff --git a/ports/stm32/usbd_msc_storage.c b/ports/stm32/usbd_msc_storage.c index f825c3d70d..7d6c19e9fe 100644 --- a/ports/stm32/usbd_msc_storage.c +++ b/ports/stm32/usbd_msc_storage.c @@ -36,7 +36,7 @@ #include "usbd_cdc_msc_hid.h" #include "usbd_msc_storage.h" -#include "py/misc.h" +#include "py/mpstate.h" #include "storage.h" #include "sdcard.h" diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h index a26b1df0dc..c2e7c17fe3 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -36,8 +36,8 @@ typedef struct { uint8_t CmdOpCode; uint8_t CmdLength; - __IO uint32_t TxState; - __IO uint32_t RxState; + volatile uint32_t TxState; + volatile uint32_t RxState; } USBD_CDC_HandleTypeDef; typedef struct _USBD_STORAGE { diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c index 379a8f32ce..81865bc00b 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -24,6 +24,7 @@ * THE SOFTWARE. */ +#include STM32_HAL_H #include "usbd_ioreq.h" #include "usbd_cdc_msc_hid.h" From 583472e06892832edc395a65096b28cd08f90764 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Feb 2018 12:46:37 +1100 Subject: [PATCH 254/828] stm32/usbdev: Combine all str descriptor accessor funcs into one func. There's no need to have these as separate functions, they just take up unnecessary code space and combining them allows to factor common code, and also allows to support arbitrary string descriptor indices. --- ports/stm32/usbd_conf.h | 1 - ports/stm32/usbd_desc.c | 163 +++++++++------------- ports/stm32/usbdev/core/inc/usbd_def.h | 10 +- ports/stm32/usbdev/core/src/usbd_ctlreq.c | 37 +---- 4 files changed, 70 insertions(+), 141 deletions(-) diff --git a/ports/stm32/usbd_conf.h b/ports/stm32/usbd_conf.h index b066bb2b81..5fa3c513d6 100644 --- a/ports/stm32/usbd_conf.h +++ b/ports/stm32/usbd_conf.h @@ -44,7 +44,6 @@ #define USBD_MAX_NUM_INTERFACES 1 #define USBD_MAX_NUM_CONFIGURATION 1 #define USBD_MAX_STR_DESC_SIZ 0x100 -#define USBD_SUPPORT_USER_STRING 0 #define USBD_SELF_POWERED 0 #define USBD_DEBUG_LEVEL 0 diff --git a/ports/stm32/usbd_desc.c b/ports/stm32/usbd_desc.c index 0c7b2dfe5a..4babebf640 100644 --- a/ports/stm32/usbd_desc.c +++ b/ports/stm32/usbd_desc.c @@ -103,115 +103,82 @@ STATIC uint8_t *USBD_DeviceDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length } /** - * @brief Returns the LangID string descriptor. - * @param speed: Current device speed + * @brief Returns a string descriptor + * @param idx: Index of the string descriptor to retrieve * @param length: Pointer to data length variable - * @retval Pointer to descriptor buffer + * @retval Pointer to descriptor buffer, or NULL if idx is invalid */ -STATIC uint8_t *USBD_LangIDStrDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { - *length = sizeof(USBD_LangIDDesc); - return (uint8_t*)USBD_LangIDDesc; // the data should only be read from this buf -} +STATIC uint8_t *USBD_StrDescriptor(USBD_HandleTypeDef *pdev, uint8_t idx, uint16_t *length) { + char str_buf[16]; + const char *str = NULL; -/** - * @brief Returns the product string descriptor. - * @param speed: Current device speed - * @param length: Pointer to data length variable - * @retval Pointer to descriptor buffer - */ -STATIC uint8_t *USBD_ProductStrDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { - uint8_t *str_desc = ((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->usbd_str_desc; - if (pdev->dev_speed == USBD_SPEED_HIGH) { - USBD_GetString((uint8_t *)USBD_PRODUCT_HS_STRING, str_desc, length); - } else { - USBD_GetString((uint8_t *)USBD_PRODUCT_FS_STRING, str_desc, length); + switch (idx) { + case USBD_IDX_LANGID_STR: + *length = sizeof(USBD_LangIDDesc); + return (uint8_t*)USBD_LangIDDesc; // the data should only be read from this buf + + case USBD_IDX_MFC_STR: + str = USBD_MANUFACTURER_STRING; + break; + + case USBD_IDX_PRODUCT_STR: + if (pdev->dev_speed == USBD_SPEED_HIGH) { + str = USBD_PRODUCT_HS_STRING; + } else { + str = USBD_PRODUCT_FS_STRING; + } + break; + + case USBD_IDX_SERIAL_STR: { + // This document: http://www.usb.org/developers/docs/devclass_docs/usbmassbulk_10.pdf + // says that the serial number has to be at least 12 digits long and that + // the last 12 digits need to be unique. It also stipulates that the valid + // character set is that of upper-case hexadecimal digits. + // + // The onboard DFU bootloader produces a 12-digit serial number based on + // the 96-bit unique ID, so for consistency we go with this algorithm. + // You can see the serial number if you use: lsusb -v + // + // See: https://my.st.com/52d187b7 for the algorithim used. + + uint8_t *id = (uint8_t *)MP_HAL_UNIQUE_ID_ADDRESS; + snprintf(str_buf, sizeof(str_buf), + "%02X%02X%02X%02X%02X%02X", + id[11], id[10] + id[2], id[9], id[8] + id[0], id[7], id[6]); + + str = str_buf; + break; + } + + case USBD_IDX_CONFIG_STR: + if (pdev->dev_speed == USBD_SPEED_HIGH) { + str = USBD_CONFIGURATION_HS_STRING; + } else { + str = USBD_CONFIGURATION_FS_STRING; + } + break; + + case USBD_IDX_INTERFACE_STR: + if (pdev->dev_speed == USBD_SPEED_HIGH) { + str = USBD_INTERFACE_HS_STRING; + } else { + str = USBD_INTERFACE_FS_STRING; + } + break; + + default: + // invalid string index + return NULL; } - return str_desc; -} - -/** - * @brief Returns the manufacturer string descriptor. - * @param speed: Current device speed - * @param length: Pointer to data length variable - * @retval Pointer to descriptor buffer - */ -STATIC uint8_t *USBD_ManufacturerStrDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { - uint8_t *str_desc = ((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->usbd_str_desc; - USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, str_desc, length); - return str_desc; -} - -/** - * @brief Returns the serial number string descriptor. - * @param speed: Current device speed - * @param length: Pointer to data length variable - * @retval Pointer to descriptor buffer - */ -STATIC uint8_t *USBD_SerialStrDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { - // This document: http://www.usb.org/developers/docs/devclass_docs/usbmassbulk_10.pdf - // says that the serial number has to be at least 12 digits long and that - // the last 12 digits need to be unique. It also stipulates that the valid - // character set is that of upper-case hexadecimal digits. - // - // The onboard DFU bootloader produces a 12-digit serial number based on - // the 96-bit unique ID, so for consistency we go with this algorithm. - // You can see the serial number if you do: - // - // dfu-util -l - // - // See: https://my.st.com/52d187b7 for the algorithim used. - - uint8_t *id = (uint8_t *)MP_HAL_UNIQUE_ID_ADDRESS; - char serial_buf[16]; - snprintf(serial_buf, sizeof(serial_buf), - "%02X%02X%02X%02X%02X%02X", - id[11], id[10] + id[2], id[9], id[8] + id[0], id[7], id[6]); uint8_t *str_desc = ((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->usbd_str_desc; - USBD_GetString((uint8_t *)serial_buf, str_desc, length); - return str_desc; -} - -/** - * @brief Returns the configuration string descriptor. - * @param speed: Current device speed - * @param length: Pointer to data length variable - * @retval Pointer to descriptor buffer - */ -STATIC uint8_t *USBD_ConfigStrDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { - uint8_t *str_desc = ((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->usbd_str_desc; - if (pdev->dev_speed == USBD_SPEED_HIGH) { - USBD_GetString((uint8_t *)USBD_CONFIGURATION_HS_STRING, str_desc, length); - } else { - USBD_GetString((uint8_t *)USBD_CONFIGURATION_FS_STRING, str_desc, length); - } - return str_desc; -} - -/** - * @brief Returns the interface string descriptor. - * @param speed: Current device speed - * @param length: Pointer to data length variable - * @retval Pointer to descriptor buffer - */ -STATIC uint8_t *USBD_InterfaceStrDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { - uint8_t *str_desc = ((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->usbd_str_desc; - if (pdev->dev_speed == USBD_SPEED_HIGH) { - USBD_GetString((uint8_t *)USBD_INTERFACE_HS_STRING, str_desc, length); - } else { - USBD_GetString((uint8_t *)USBD_INTERFACE_FS_STRING, str_desc, length); - } + USBD_GetString((uint8_t*)str, str_desc, length); return str_desc; } const USBD_DescriptorsTypeDef USBD_Descriptors = { USBD_DeviceDescriptor, - USBD_LangIDStrDescriptor, - USBD_ManufacturerStrDescriptor, - USBD_ProductStrDescriptor, - USBD_SerialStrDescriptor, - USBD_ConfigStrDescriptor, - USBD_InterfaceStrDescriptor, + USBD_StrDescriptor, }; /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/usbdev/core/inc/usbd_def.h b/ports/stm32/usbdev/core/inc/usbd_def.h index 888d426ef3..1402062964 100644 --- a/ports/stm32/usbdev/core/inc/usbd_def.h +++ b/ports/stm32/usbdev/core/inc/usbd_def.h @@ -172,9 +172,6 @@ typedef struct _Device_cb uint8_t *(*GetFSConfigDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); uint8_t *(*GetOtherSpeedConfigDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); uint8_t *(*GetDeviceQualifierDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); -#if (USBD_SUPPORT_USER_STRING == 1) - uint8_t *(*GetUsrStrDescriptor)(struct _USBD_HandleTypeDef *pdev ,uint8_t index, uint16_t *length); -#endif } USBD_ClassTypeDef; @@ -199,12 +196,7 @@ struct _USBD_HandleTypeDef; typedef struct { uint8_t *(*GetDeviceDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); - uint8_t *(*GetLangIDStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); - uint8_t *(*GetManufacturerStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); - uint8_t *(*GetProductStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); - uint8_t *(*GetSerialStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); - uint8_t *(*GetConfigurationStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); - uint8_t *(*GetInterfaceStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); + uint8_t *(*GetStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint8_t idx, uint16_t *length); } USBD_DescriptorsTypeDef; /* USB Device handle structure */ diff --git a/ports/stm32/usbdev/core/src/usbd_ctlreq.c b/ports/stm32/usbdev/core/src/usbd_ctlreq.c index 5fba322fa6..a68016bf45 100644 --- a/ports/stm32/usbdev/core/src/usbd_ctlreq.c +++ b/ports/stm32/usbdev/core/src/usbd_ctlreq.c @@ -347,42 +347,13 @@ static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev , break; case USB_DESC_TYPE_STRING: - switch ((uint8_t)(req->wValue)) - { - case USBD_IDX_LANGID_STR: - pbuf = pdev->pDesc->GetLangIDStrDescriptor(pdev, &len); - break; - - case USBD_IDX_MFC_STR: - pbuf = pdev->pDesc->GetManufacturerStrDescriptor(pdev, &len); - break; - - case USBD_IDX_PRODUCT_STR: - pbuf = pdev->pDesc->GetProductStrDescriptor(pdev, &len); - break; - - case USBD_IDX_SERIAL_STR: - pbuf = pdev->pDesc->GetSerialStrDescriptor(pdev, &len); - break; - - case USBD_IDX_CONFIG_STR: - pbuf = pdev->pDesc->GetConfigurationStrDescriptor(pdev, &len); - break; - - case USBD_IDX_INTERFACE_STR: - pbuf = pdev->pDesc->GetInterfaceStrDescriptor(pdev, &len); - break; - - default: -#if (USBD_SUPPORT_USER_STRING == 1) - pbuf = pdev->pClass->GetUsrStrDescriptor(pdev, (req->wValue) , &len); - break; -#else - USBD_CtlError(pdev , req); + pbuf = pdev->pDesc->GetStrDescriptor(pdev, req->wValue & 0xff, &len); + if (pbuf == NULL) { + USBD_CtlError(pdev, req); return; -#endif } break; + case USB_DESC_TYPE_DEVICE_QUALIFIER: if(pdev->dev_speed == USBD_SPEED_HIGH ) From 4e35d108298b0f9ab6554f3c897a7147b9f83843 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Feb 2018 13:11:02 +1100 Subject: [PATCH 255/828] stm32/can: Support MCUs without a CAN2 peripheral. --- ports/stm32/can.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ports/stm32/can.c b/ports/stm32/can.c index 25a608ce9b..d71a8bec7e 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -106,6 +106,7 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { __CAN1_CLK_ENABLE(); break; + #if defined(CAN2) // CAN2 is on RX,TX = Y5,Y6 = PB12,PB13 case PYB_CAN_2: CANx = CAN2; @@ -115,6 +116,7 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { __CAN1_CLK_ENABLE(); // CAN2 is a "slave" and needs CAN1 enabled as well __CAN2_CLK_ENABLE(); break; + #endif default: return false; @@ -416,12 +418,14 @@ STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in) { __CAN1_FORCE_RESET(); __CAN1_RELEASE_RESET(); __CAN1_CLK_DISABLE(); + #if defined(CAN2) } else if (self->can.Instance == CAN2) { HAL_NVIC_DisableIRQ(CAN2_RX0_IRQn); HAL_NVIC_DisableIRQ(CAN2_RX1_IRQn); __CAN2_FORCE_RESET(); __CAN2_RELEASE_RESET(); __CAN2_CLK_DISABLE(); + #endif } return mp_const_none; } @@ -760,11 +764,13 @@ STATIC mp_obj_t pyb_can_rxcallback(mp_obj_t self_in, mp_obj_t fifo_in, mp_obj_t *callback = callback_in; } else if (mp_obj_is_callable(callback_in)) { *callback = callback_in; - uint32_t irq; + uint32_t irq = 0; if (self->can_id == PYB_CAN_1) { irq = (fifo == 0) ? CAN1_RX0_IRQn : CAN1_RX1_IRQn; + #if defined(CAN2) } else { irq = (fifo == 0) ? CAN2_RX0_IRQn : CAN2_RX1_IRQn; + #endif } HAL_NVIC_SetPriority(irq, IRQ_PRI_CAN, IRQ_SUBPRI_CAN); HAL_NVIC_EnableIRQ(irq); From e8a8fa77ca309a357e31e9eafc24072d4dfd619d Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Feb 2018 13:11:32 +1100 Subject: [PATCH 256/828] stm32: Improve support for STM32F722, F723, F732, F733 MCUs. --- ports/stm32/adc.c | 8 ++++++++ ports/stm32/mphalport.h | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 9a0dc56a37..0e1cf4b646 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -66,7 +66,13 @@ #define ADC_FIRST_GPIO_CHANNEL (0) #define ADC_LAST_GPIO_CHANNEL (15) +#if defined(STM32F722xx) || defined(STM32F723xx) || \ + defined(STM32F732xx) || defined(STM32F733xx) +#define ADC_CAL_ADDRESS (0x1ff07a2a) +#else #define ADC_CAL_ADDRESS (0x1ff0f44a) +#endif + #define ADC_CAL1 ((uint16_t*)(ADC_CAL_ADDRESS + 2)) #define ADC_CAL2 ((uint16_t*)(ADC_CAL_ADDRESS + 4)) @@ -91,6 +97,8 @@ #define VBAT_DIV (2) #elif defined(STM32F427xx) || defined(STM32F429xx) || \ defined(STM32F437xx) || defined(STM32F439xx) || \ + defined(STM32F722xx) || defined(STM32F723xx) || \ + defined(STM32F732xx) || defined(STM32F733xx) || \ defined(STM32F746xx) || defined(STM32F767xx) || \ defined(STM32F769xx) || defined(STM32F446xx) #define VBAT_DIV (4) diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h index 939df0b3d2..8224c9f5a4 100644 --- a/ports/stm32/mphalport.h +++ b/ports/stm32/mphalport.h @@ -9,7 +9,14 @@ #define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size) #define MP_HAL_CLEAN_DCACHE(addr, size) #elif defined(MCU_SERIES_F7) +#if defined(STM32F722xx) \ + || defined(STM32F723xx) \ + || defined(STM32F732xx) \ + || defined(STM32F733xx) +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff07a10) +#else #define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff0f420) +#endif #define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size) (SCB_CleanInvalidateDCache_by_Addr((uint32_t*)((uint32_t)addr & ~0x1f), ((uint32_t)((uint8_t*)addr + size + 0x1f) & ~0x1f) - ((uint32_t)addr & ~0x1f))) #define MP_HAL_CLEAN_DCACHE(addr, size) (SCB_CleanDCache_by_Addr((uint32_t*)((uint32_t)addr & ~0x1f), ((uint32_t)((uint8_t*)addr + size + 0x1f) & ~0x1f) - ((uint32_t)addr & ~0x1f))) #elif defined(MCU_SERIES_L4) From 9e7d2c7abb06a850c664e24b7d8fe5aafee4e443 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Feb 2018 14:06:18 +1100 Subject: [PATCH 257/828] stm32/modmachine: In freq(), select flash latency value based on freq. --- ports/stm32/modmachine.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index d9eb6383e7..fba27a3bb2 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -359,27 +359,44 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { // set PLL as system clock source if wanted if (sysclk_source == RCC_SYSCLKSOURCE_PLLCLK) { + uint32_t flash_latency; #if defined(MCU_SERIES_F7) // if possible, scale down the internal voltage regulator to save power + // the flash_latency values assume a supply voltage between 2.7V and 3.6V uint32_t volt_scale; - if (wanted_sysclk <= 151000000) { + if (wanted_sysclk <= 90000000) { volt_scale = PWR_REGULATOR_VOLTAGE_SCALE3; + flash_latency = FLASH_LATENCY_2; + } else if (wanted_sysclk <= 120000000) { + volt_scale = PWR_REGULATOR_VOLTAGE_SCALE3; + flash_latency = FLASH_LATENCY_3; + } else if (wanted_sysclk <= 144000000) { + volt_scale = PWR_REGULATOR_VOLTAGE_SCALE3; + flash_latency = FLASH_LATENCY_4; } else if (wanted_sysclk <= 180000000) { volt_scale = PWR_REGULATOR_VOLTAGE_SCALE2; + flash_latency = FLASH_LATENCY_5; + } else if (wanted_sysclk <= 210000000) { + volt_scale = PWR_REGULATOR_VOLTAGE_SCALE1; + flash_latency = FLASH_LATENCY_6; } else { volt_scale = PWR_REGULATOR_VOLTAGE_SCALE1; + flash_latency = FLASH_LATENCY_7; } if (HAL_PWREx_ControlVoltageScaling(volt_scale) != HAL_OK) { goto fail; } #endif + #if !defined(MCU_SERIES_F7) #if !defined(MICROPY_HW_FLASH_LATENCY) #define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_5 #endif + flash_latency = MICROPY_HW_FLASH_LATENCY; + #endif RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; - if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, MICROPY_HW_FLASH_LATENCY) != HAL_OK) { + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, flash_latency) != HAL_OK) { goto fail; } } From 467a5926bc57549f36055938b8bbf7f9bf0dd101 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Feb 2018 15:02:04 +1100 Subject: [PATCH 258/828] stm32/sdcard: Only define IRQ handler if using SDMMC1 peripheral. So that the IRQ can be used by other peripheral drivers if needed. --- ports/stm32/sdcard.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index 46f08f78f6..b8a73daaf6 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -227,11 +227,13 @@ uint64_t sdcard_get_capacity_in_bytes(void) { return (uint64_t)cardinfo.LogBlockNbr * (uint64_t)cardinfo.LogBlockSize; } +#if !defined(MICROPY_HW_SDMMC2_CK) void SDIO_IRQHandler(void) { IRQ_ENTER(SDIO_IRQn); HAL_SD_IRQHandler(&sd_handle); IRQ_EXIT(SDIO_IRQn); } +#endif #if defined(MCU_SERIES_F7) void SDMMC2_IRQHandler(void) { From 72ca049de732dc6d8e30385517d835fa7d56e5e0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Feb 2018 15:17:18 +1100 Subject: [PATCH 259/828] stm32/sdcard: Use maximum speed SDMMC clock on F7 MCUs. This will get the SDMMC clock up to 48MHz. --- ports/stm32/sdcard.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index b8a73daaf6..9b087ef849 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -198,6 +198,10 @@ bool sdcard_power_on(void) { } // configure the SD bus width for wide operation + #if defined(MCU_SERIES_F7) + // use maximum SDMMC clock speed on F7 MCUs + sd_handle.Init.ClockBypass = SDMMC_CLOCK_BYPASS_ENABLE; + #endif if (HAL_SD_ConfigWideBusOperation(&sd_handle, SDIO_BUS_WIDE_4B) != HAL_OK) { HAL_SD_DeInit(&sd_handle); goto error; From 3130424b542726baef337a86ffce142a5786071b Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Feb 2018 15:47:16 +1100 Subject: [PATCH 260/828] stm32/usbdev: Add support for MSC-only USB device class. Select this mode in boot.py via: pyb.usb_mode('MSC') --- ports/stm32/usb.c | 5 ++ ports/stm32/usb.h | 1 + .../stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 54 +++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 69f381d9b3..1544b1d9c5 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -293,6 +293,11 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * pid = USBD_PID_CDC; } mode = USBD_MODE_CDC; + } else if (strcmp(mode_str, "MSC") == 0) { + if (args[2].u_int == -1) { + pid = USBD_PID_MSC; + } + mode = USBD_MODE_MSC; } else { goto bad_mode; } diff --git a/ports/stm32/usb.h b/ports/stm32/usb.h index 41c461fb2f..c75d59e477 100644 --- a/ports/stm32/usb.h +++ b/ports/stm32/usb.h @@ -35,6 +35,7 @@ #define USBD_PID_CDC_MSC (0x9800) #define USBD_PID_CDC_HID (0x9801) #define USBD_PID_CDC (0x9802) +#define USBD_PID_MSC (0x9803) typedef enum { PYB_USB_STORAGE_MEDIUM_NONE = 0, diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c index 81865bc00b..e566f34e8e 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -28,6 +28,7 @@ #include "usbd_ioreq.h" #include "usbd_cdc_msc_hid.h" +#define MSC_TEMPLATE_CONFIG_DESC_SIZE (32) #define CDC_TEMPLATE_CONFIG_DESC_SIZE (67) #define CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE (98) #define CDC_HID_TEMPLATE_CONFIG_DESC_SIZE (107) @@ -89,6 +90,54 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_MSC_HID_DeviceQualifierDesc[USB_LEN_DEV_QU }; */ +// USB MSC device Configuration Descriptor +static const uint8_t msc_template_config_desc[MSC_TEMPLATE_CONFIG_DESC_SIZE] = { + //-------------------------------------------------------------------------- + // Configuration Descriptor + 0x09, // bLength: Configuration Descriptor size + USB_DESC_TYPE_CONFIGURATION, // bDescriptorType: Configuration + LOBYTE(MSC_TEMPLATE_CONFIG_DESC_SIZE), // wTotalLength: no of returned bytes + HIBYTE(MSC_TEMPLATE_CONFIG_DESC_SIZE), + 0x01, // bNumInterfaces: 1 interfaces + 0x01, // bConfigurationValue: Configuration value + 0x00, // iConfiguration: Index of string descriptor describing the configuration + 0x80, // bmAttributes: bus powered; 0xc0 for self powered + 0xfa, // bMaxPower: in units of 2mA + + //========================================================================== + // MSC only has 1 interface so doesn't need an IAD + + //-------------------------------------------------------------------------- + // Interface Descriptor + 0x09, // bLength: Interface Descriptor size + USB_DESC_TYPE_INTERFACE, // bDescriptorType: interface descriptor + MSC_IFACE_NUM_WITH_CDC, // bInterfaceNumber: Number of Interface + 0x00, // bAlternateSetting: Alternate setting + 0x02, // bNumEndpoints + 0x08, // bInterfaceClass: MSC Class + 0x06, // bInterfaceSubClass : SCSI transparent + 0x50, // nInterfaceProtocol + 0x00, // iInterface: + + // Endpoint IN descriptor + 0x07, // bLength: Endpoint descriptor length + USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type + MSC_IN_EP, // bEndpointAddress: IN, address 3 + 0x02, // bmAttributes: Bulk endpoint type + LOBYTE(MSC_MAX_PACKET), // wMaxPacketSize + HIBYTE(MSC_MAX_PACKET), + 0x00, // bInterval: ignore for Bulk transfer + + // Endpoint OUT descriptor + 0x07, // bLength: Endpoint descriptor length + USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type + MSC_OUT_EP, // bEndpointAddress: OUT, address 3 + 0x02, // bmAttributes: Bulk endpoint type + LOBYTE(MSC_MAX_PACKET), // wMaxPacketSize + HIBYTE(MSC_MAX_PACKET), + 0x00, // bInterval: ignore for Bulk transfer +}; + // USB CDC MSC device Configuration Descriptor static const uint8_t cdc_msc_template_config_desc[CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE] = { //-------------------------------------------------------------------------- @@ -554,6 +603,11 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode // construct config desc switch (usbd->usbd_mode) { + case USBD_MODE_MSC: + usbd->usbd_config_desc_size = sizeof(msc_template_config_desc); + memcpy(usbd->usbd_config_desc, msc_template_config_desc, sizeof(msc_template_config_desc)); + break; + case USBD_MODE_CDC_MSC: usbd->usbd_config_desc_size = sizeof(cdc_msc_template_config_desc); memcpy(usbd->usbd_config_desc, cdc_msc_template_config_desc, sizeof(cdc_msc_template_config_desc)); From e708e87139ec2bd2c94ce33c0f7b873ef89d3827 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Feb 2018 15:52:49 +1100 Subject: [PATCH 261/828] docs/library/pyb.rst: Add note about availability of USB MSC-only mode. --- docs/library/pyb.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/library/pyb.rst b/docs/library/pyb.rst index 7991601457..141c270b31 100644 --- a/docs/library/pyb.rst +++ b/docs/library/pyb.rst @@ -278,7 +278,8 @@ Miscellaneous functions - ``None``: disables USB - ``'VCP'``: enable with VCP (Virtual COM Port) interface - - ``'VCP+MSC'``: enable with VCP and MSC (mass storage device class) + - ``'MSC'``: enable with MSC (mass storage device class) interface + - ``'VCP+MSC'``: enable with VCP and MSC - ``'VCP+HID'``: enable with VCP and HID (human interface device) For backwards compatibility, ``'CDC'`` is understood to mean From 71312d0bd10d47e958cca71ed6f6ce5bbdc93f88 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Feb 2018 17:47:28 +1100 Subject: [PATCH 262/828] stm32/usb: Allow board to select which USBD is used as the main one. By defining MICROPY_HW_USB_MAIN_DEV a given board can select to use either USB_PHY_FS_ID or USB_PHY_HS_ID as the main USBD peripheral, on which the REPL will appear. If not defined this will be automatically configured. --- ports/stm32/usb.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 1544b1d9c5..634c9e6f41 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -42,12 +42,15 @@ #include "bufhelper.h" #include "usb.h" +// Work out which USB device to use as the main one (the one with the REPL) +#if !defined(MICROPY_HW_USB_MAIN_DEV) #if defined(USE_USB_FS) -#define USB_PHY_ID USB_PHY_FS_ID +#define MICROPY_HW_USB_MAIN_DEV (USB_PHY_FS_ID) #elif defined(USE_USB_HS) && defined(USE_USB_HS_IN_FS) -#define USB_PHY_ID USB_PHY_HS_ID +#define MICROPY_HW_USB_MAIN_DEV (USB_PHY_HS_ID) #else -#error Unable to determine proper USB_PHY_ID to use +#error Unable to determine proper MICROPY_HW_USB_MAIN_DEV to use +#endif #endif // this will be persistent across a soft-reset @@ -123,7 +126,7 @@ bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_H // set up the USBD state USBD_HandleTypeDef *usbd = &usb_dev->hUSBDDevice; - usbd->id = USB_PHY_ID; + usbd->id = MICROPY_HW_USB_MAIN_DEV; usbd->dev_state = USBD_STATE_DEFAULT; usbd->pDesc = (USBD_DescriptorsTypeDef*)&USBD_Descriptors; usbd->pClass = &USBD_CDC_MSC_HID; From db702ba722fdf266a653d885e568c0088d109d13 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Feb 2018 17:57:44 +1100 Subject: [PATCH 263/828] stm32/usbdev: Add support for high-speed USB device mode. This patch adds support in the USBD configuration and CDC-MSC-HID class for high-speed USB mode. To enable it the board configuration must define USE_USB_HS, and either not define USE_USB_HS_IN_FS, or be an STM32F723 or STM32F733 MCU which have a built-in HS PHY. High-speed mode is then selected dynamically by passing "high_speed=True" to the pyb.usb_mode() function, otherwise it defaults to full-speed mode. This patch has been tested on an STM32F733. --- ports/stm32/usb.c | 13 +- ports/stm32/usbd_cdc_interface.c | 2 +- ports/stm32/usbd_cdc_interface.h | 2 +- ports/stm32/usbd_conf.c | 34 +++-- .../stm32/usbdev/class/inc/usbd_cdc_msc_hid.h | 41 +++++- .../usbdev/class/inc/usbd_cdc_msc_hid0.h | 1 + .../stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 118 ++++++++++++++---- ports/stm32/usbdev/core/inc/usbd_core.h | 2 +- ports/stm32/usbdev/core/src/usbd_core.c | 2 +- 9 files changed, 175 insertions(+), 40 deletions(-) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 634c9e6f41..e134781b45 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -114,6 +114,8 @@ void pyb_usb_init0(void) { bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_HID_ModeInfoTypeDef *hid_info) { #ifdef USE_DEVICE_MODE + bool high_speed = (mode & USBD_MODE_HIGH_SPEED) != 0; + mode &= 0x7f; usb_device_t *usb_dev = &usb_device; if (!usb_dev->enabled) { // only init USB once in the device's power-lifetime @@ -147,7 +149,7 @@ bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_H } // start the USB device - USBD_LL_Init(usbd); + USBD_LL_Init(usbd, high_speed); USBD_LL_Start(usbd); usb_dev->enabled = true; } @@ -215,6 +217,9 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * { MP_QSTR_vid, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = USBD_VID} }, { MP_QSTR_pid, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_hid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = (mp_obj_t)&pyb_usb_hid_mouse_obj} }, + #if USBD_SUPPORT_HS_MODE + { MP_QSTR_high_speed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + #endif }; // fetch the current usb mode -> pyb.usb_mode() @@ -323,6 +328,12 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * MP_STATE_PORT(pyb_hid_report_desc) = items[4]; } + #if USBD_SUPPORT_HS_MODE + if (args[4].u_bool) { + mode |= USBD_MODE_HIGH_SPEED; + } + #endif + // init the USB device if (!pyb_usb_dev_init(vid, pid, mode, &hid_info)) { goto bad_mode; diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c index 2e9fba917c..23085510cc 100644 --- a/ports/stm32/usbd_cdc_interface.c +++ b/ports/stm32/usbd_cdc_interface.c @@ -198,7 +198,7 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { // the host waits for all data to arrive (ie, waits for a packet < max packet size). // To flush a packet of exactly max packet size, we need to send a zero-size packet. // See eg http://www.cypress.com/?id=4&rID=92719 - cdc->tx_need_empty_packet = (buffsize > 0 && buffsize % CDC_DATA_FS_MAX_PACKET_SIZE == 0 && cdc->tx_buf_ptr_out_shadow == cdc->tx_buf_ptr_in); + cdc->tx_need_empty_packet = (buffsize > 0 && buffsize % usbd_cdc_max_packet(usbd->pdev) == 0 && cdc->tx_buf_ptr_out_shadow == cdc->tx_buf_ptr_in); } } } diff --git a/ports/stm32/usbd_cdc_interface.h b/ports/stm32/usbd_cdc_interface.h index 98b8fc077d..44926085a8 100644 --- a/ports/stm32/usbd_cdc_interface.h +++ b/ports/stm32/usbd_cdc_interface.h @@ -37,7 +37,7 @@ typedef struct _usbd_cdc_itf_t { usbd_cdc_msc_hid_state_t *usbd; // the parent USB device - uint8_t rx_packet_buf[CDC_DATA_FS_MAX_PACKET_SIZE]; // received data from USB OUT endpoint is stored in this buffer + uint8_t rx_packet_buf[CDC_DATA_MAX_PACKET_SIZE]; // received data from USB OUT endpoint is stored in this buffer uint8_t rx_user_buf[USBD_CDC_RX_DATA_SIZE]; // received data is buffered here until the user reads it volatile uint16_t rx_buf_put; // circular buffer index uint16_t rx_buf_get; // circular buffer index diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index d39144851f..910c748d88 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -152,10 +152,19 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) * Enable calling WFI and correct * function of the embedded USB_FS_IN_HS phy */ - __OTGHSULPI_CLK_SLEEP_DISABLE(); - __OTGHS_CLK_SLEEP_ENABLE(); + __HAL_RCC_USB_OTG_HS_ULPI_CLK_SLEEP_DISABLE(); + __HAL_RCC_USB_OTG_HS_CLK_SLEEP_ENABLE(); + /* Enable USB HS Clocks */ - __USB_OTG_HS_CLK_ENABLE(); + + #if defined(STM32F723xx) || defined(STM32F733xx) + // Needs to remain awake during sleep or else __WFI() will disable the USB + __HAL_RCC_USB_OTG_HS_ULPI_CLK_SLEEP_ENABLE(); + __HAL_RCC_OTGPHYC_CLK_ENABLE(); + __HAL_RCC_USB_OTG_HS_ULPI_CLK_ENABLE(); + #endif + + __HAL_RCC_USB_OTG_HS_CLK_ENABLE(); #else // !USE_USB_HS_IN_FS @@ -399,7 +408,7 @@ void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) * @param pdev: Device handle * @retval USBD Status */ -USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev) +USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev, int high_speed) { #if defined(USE_USB_FS) if (pdev->id == USB_PHY_FS_ID) @@ -447,25 +456,34 @@ if (pdev->id == USB_PHY_HS_ID) pcd_hs_handle.Init.ep0_mps = 0x40; pcd_hs_handle.Init.dma_enable = 0; pcd_hs_handle.Init.low_power_enable = 0; + #if defined(STM32F723xx) || defined(STM32F733xx) + pcd_hs_handle.Init.phy_itface = USB_OTG_HS_EMBEDDED_PHY; + #else pcd_hs_handle.Init.phy_itface = PCD_PHY_EMBEDDED; + #endif pcd_hs_handle.Init.Sof_enable = 1; - pcd_hs_handle.Init.speed = PCD_SPEED_HIGH_IN_FULL; + if (high_speed) { + pcd_hs_handle.Init.speed = PCD_SPEED_HIGH; + } else { + pcd_hs_handle.Init.speed = PCD_SPEED_HIGH_IN_FULL; + } #if !defined(MICROPY_HW_USB_VBUS_DETECT_PIN) pcd_hs_handle.Init.vbus_sensing_enable = 0; // No VBUS Sensing on USB0 #else pcd_hs_handle.Init.vbus_sensing_enable = 1; #endif + pcd_hs_handle.Init.use_external_vbus = 0; /* Link The driver to the stack */ pcd_hs_handle.pData = pdev; pdev->pData = &pcd_hs_handle; /*Initialize LL Driver */ HAL_PCD_Init(&pcd_hs_handle); - HAL_PCD_SetRxFiFo(&pcd_hs_handle, 0x80); + HAL_PCD_SetRxFiFo(&pcd_hs_handle, 0x200); HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 0x20); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 0x40); + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 0x100); HAL_PCD_SetTxFiFo(&pcd_hs_handle, 2, 0x20); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 0x40); + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 0xc0); #else // !defined(USE_USB_HS_IN_FS) /*Set LL Driver parameters */ pcd_hs_handle.Instance = USB_OTG_HS; diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h index c2e7c17fe3..600d863790 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -5,13 +5,30 @@ #include "usbd_msc_bot.h" #include "usbd_msc_scsi.h" #include "usbd_ioreq.h" +#include STM32_HAL_H + +// Work out if we should support USB high-speed device mode +#if defined(USE_USB_HS) \ + && (!defined(USE_USB_HS_IN_FS) || defined(STM32F723xx) || defined(STM32F733xx)) +#define USBD_SUPPORT_HS_MODE (1) +#else +#define USBD_SUPPORT_HS_MODE (0) +#endif // Needed for the CDC+MSC+HID state and should be maximum of all template // config descriptors defined in usbd_cdc_msc_hid.c #define MAX_TEMPLATE_CONFIG_DESC_SIZE (107) // CDC, MSC and HID packet sizes +#define MSC_FS_MAX_PACKET (64) +#define MSC_HS_MAX_PACKET (512) #define CDC_DATA_FS_MAX_PACKET_SIZE (64) // endpoint IN & OUT packet size +#define CDC_DATA_HS_MAX_PACKET_SIZE (512) // endpoint IN & OUT packet size +#if USBD_SUPPORT_HS_MODE +#define CDC_DATA_MAX_PACKET_SIZE CDC_DATA_HS_MAX_PACKET_SIZE +#else +#define CDC_DATA_MAX_PACKET_SIZE CDC_DATA_FS_MAX_PACKET_SIZE +#endif #define MSC_MEDIA_PACKET (2048) // was 8192; how low can it go whilst still working? #define HID_DATA_FS_MAX_PACKET_SIZE (64) // endpoint IN & OUT packet size @@ -32,7 +49,7 @@ typedef struct { } USBD_CDC_LineCodingTypeDef; typedef struct { - uint32_t data[CDC_DATA_FS_MAX_PACKET_SIZE/4]; /* Force 32bits alignment */ + uint32_t data[CDC_DATA_MAX_PACKET_SIZE / 4]; // Force 32bits alignment uint8_t CmdOpCode; uint8_t CmdLength; @@ -126,6 +143,28 @@ extern const uint8_t USBD_HID_KEYBOARD_ReportDesc[USBD_HID_KEYBOARD_REPORT_DESC_ extern const USBD_ClassTypeDef USBD_CDC_MSC_HID; +static inline uint32_t usbd_msc_max_packet(USBD_HandleTypeDef *pdev) { + #if USBD_SUPPORT_HS_MODE + if (pdev->dev_speed == USBD_SPEED_HIGH) { + return MSC_HS_MAX_PACKET; + } else + #endif + { + return MSC_FS_MAX_PACKET; + } +} + +static inline uint32_t usbd_cdc_max_packet(USBD_HandleTypeDef *pdev) { + #if USBD_SUPPORT_HS_MODE + if (pdev->dev_speed == USBD_SPEED_HIGH) { + return CDC_DATA_HS_MAX_PACKET_SIZE; + } else + #endif + { + return CDC_DATA_FS_MAX_PACKET_SIZE; + } +} + // returns 0 on success, -1 on failure int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info); // returns the current usb mode diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h index 08882bb1ae..3bf7bccfdd 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h @@ -37,6 +37,7 @@ typedef enum { USBD_MODE_CDC_MSC = 0x03, USBD_MODE_CDC_HID = 0x05, USBD_MODE_MSC_HID = 0x06, + USBD_MODE_HIGH_SPEED = 0x80, // or with one of the above } usb_device_mode_t; typedef struct _USBD_HID_ModeInfoTypeDef { diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c index e566f34e8e..394fceb75c 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -29,10 +29,20 @@ #include "usbd_cdc_msc_hid.h" #define MSC_TEMPLATE_CONFIG_DESC_SIZE (32) +#define MSC_TEMPLATE_MSC_DESC_OFFSET (9) #define CDC_TEMPLATE_CONFIG_DESC_SIZE (67) #define CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE (98) +#define CDC_MSC_TEMPLATE_MSC_DESC_OFFSET (9) +#define CDC_MSC_TEMPLATE_CDC_DESC_OFFSET (40) #define CDC_HID_TEMPLATE_CONFIG_DESC_SIZE (107) #define CDC_HID_TEMPLATE_HID_DESC_OFFSET (9) +#define CDC_HID_TEMPLATE_CDC_DESC_OFFSET (49) +#define CDC_TEMPLATE_CDC_DESC_OFFSET (9) +#define CDC_DESC_OFFSET_INTR_INTERVAL (34) +#define CDC_DESC_OFFSET_OUT_MAX_PACKET_LO (48) +#define CDC_DESC_OFFSET_OUT_MAX_PACKET_HI (49) +#define CDC_DESC_OFFSET_IN_MAX_PACKET_LO (55) +#define CDC_DESC_OFFSET_IN_MAX_PACKET_HI (56) #define HID_DESC_OFFSET_SUBCLASS (6) #define HID_DESC_OFFSET_PROTOCOL (7) #define HID_DESC_OFFSET_SUBDESC (9) @@ -59,10 +69,7 @@ #define USB_DESC_TYPE_ASSOCIATION (0x0b) #define CDC_CMD_PACKET_SIZE (8) // Control Endpoint Packet size -#define CDC_DATA_IN_PACKET_SIZE CDC_DATA_FS_MAX_PACKET_SIZE -#define CDC_DATA_OUT_PACKET_SIZE CDC_DATA_FS_MAX_PACKET_SIZE -#define MSC_MAX_PACKET (0x40) #define BOT_GET_MAX_LUN (0xfe) #define BOT_RESET (0xff) @@ -73,8 +80,7 @@ #define HID_REQ_SET_IDLE (0x0a) #define HID_REQ_GET_IDLE (0x02) -/* -// this is used only in high-speed mode, which we don't support +#if USBD_SUPPORT_HS_MODE // USB Standard Device Descriptor __ALIGN_BEGIN static uint8_t USBD_CDC_MSC_HID_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END = { USB_LEN_DEV_QUALIFIER_DESC, @@ -84,11 +90,11 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_MSC_HID_DeviceQualifierDesc[USB_LEN_DEV_QU 0x00, 0x00, 0x00, - 0x40, // same for CDC and MSC (latter being MSC_MAX_PACKET), HID is 0x04 + 0x40, // same for CDC and MSC (latter being MSC_FS_MAX_PACKET), HID is 0x04 0x01, 0x00, }; -*/ +#endif // USB MSC device Configuration Descriptor static const uint8_t msc_template_config_desc[MSC_TEMPLATE_CONFIG_DESC_SIZE] = { @@ -124,8 +130,8 @@ static const uint8_t msc_template_config_desc[MSC_TEMPLATE_CONFIG_DESC_SIZE] = { USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type MSC_IN_EP, // bEndpointAddress: IN, address 3 0x02, // bmAttributes: Bulk endpoint type - LOBYTE(MSC_MAX_PACKET), // wMaxPacketSize - HIBYTE(MSC_MAX_PACKET), + LOBYTE(MSC_FS_MAX_PACKET), // wMaxPacketSize + HIBYTE(MSC_FS_MAX_PACKET), 0x00, // bInterval: ignore for Bulk transfer // Endpoint OUT descriptor @@ -133,8 +139,8 @@ static const uint8_t msc_template_config_desc[MSC_TEMPLATE_CONFIG_DESC_SIZE] = { USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type MSC_OUT_EP, // bEndpointAddress: OUT, address 3 0x02, // bmAttributes: Bulk endpoint type - LOBYTE(MSC_MAX_PACKET), // wMaxPacketSize - HIBYTE(MSC_MAX_PACKET), + LOBYTE(MSC_FS_MAX_PACKET), // wMaxPacketSize + HIBYTE(MSC_FS_MAX_PACKET), 0x00, // bInterval: ignore for Bulk transfer }; @@ -172,8 +178,8 @@ static const uint8_t cdc_msc_template_config_desc[CDC_MSC_TEMPLATE_CONFIG_DESC_S USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type MSC_IN_EP, // bEndpointAddress: IN, address 3 0x02, // bmAttributes: Bulk endpoint type - LOBYTE(MSC_MAX_PACKET), // wMaxPacketSize - HIBYTE(MSC_MAX_PACKET), + LOBYTE(MSC_FS_MAX_PACKET), // wMaxPacketSize + HIBYTE(MSC_FS_MAX_PACKET), 0x00, // bInterval: ignore for Bulk transfer // Endpoint OUT descriptor @@ -181,8 +187,8 @@ static const uint8_t cdc_msc_template_config_desc[CDC_MSC_TEMPLATE_CONFIG_DESC_S USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type MSC_OUT_EP, // bEndpointAddress: OUT, address 3 0x02, // bmAttributes: Bulk endpoint type - LOBYTE(MSC_MAX_PACKET), // wMaxPacketSize - HIBYTE(MSC_MAX_PACKET), + LOBYTE(MSC_FS_MAX_PACKET), // wMaxPacketSize + HIBYTE(MSC_FS_MAX_PACKET), 0x00, // bInterval: ignore for Bulk transfer //========================================================================== @@ -663,27 +669,31 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode } static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { + #if !USBD_SUPPORT_HS_MODE if (pdev->dev_speed == USBD_SPEED_HIGH) { // can't handle high speed return 1; } + #endif usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; if (usbd->usbd_mode & USBD_MODE_CDC) { // CDC VCP component + int mp = usbd_cdc_max_packet(pdev); + // Open EP IN USBD_LL_OpenEP(pdev, CDC_IN_EP, USBD_EP_TYPE_BULK, - CDC_DATA_IN_PACKET_SIZE); + mp); // Open EP OUT USBD_LL_OpenEP(pdev, CDC_OUT_EP, USBD_EP_TYPE_BULK, - CDC_DATA_OUT_PACKET_SIZE); + mp); // Open Command IN EP USBD_LL_OpenEP(pdev, @@ -699,23 +709,25 @@ static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { usbd->CDC_ClassData.RxState = 0; // Prepare Out endpoint to receive next packet - USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, buf, CDC_DATA_OUT_PACKET_SIZE); + USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, buf, mp); } if (usbd->usbd_mode & USBD_MODE_MSC) { // MSC component + int mp = usbd_msc_max_packet(pdev); + // Open EP OUT USBD_LL_OpenEP(pdev, MSC_OUT_EP, USBD_EP_TYPE_BULK, - MSC_MAX_PACKET); + mp); // Open EP IN USBD_LL_OpenEP(pdev, MSC_IN_EP, USBD_EP_TYPE_BULK, - MSC_MAX_PACKET); + mp); // Init the BOT layer MSC_BOT_Init(pdev); @@ -903,10 +915,10 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp USBD_LL_CloseEP(pdev, (uint8_t)req->wIndex); if((((uint8_t)req->wIndex) & 0x80) == 0x80) { // Open EP IN - USBD_LL_OpenEP(pdev, MSC_IN_EP, USBD_EP_TYPE_BULK, MSC_MAX_PACKET); + USBD_LL_OpenEP(pdev, MSC_IN_EP, USBD_EP_TYPE_BULK, usbd_msc_max_packet(pdev)); } else { // Open EP OUT - USBD_LL_OpenEP(pdev, MSC_OUT_EP, USBD_EP_TYPE_BULK, MSC_MAX_PACKET); + USBD_LL_OpenEP(pdev, MSC_OUT_EP, USBD_EP_TYPE_BULK, usbd_msc_max_packet(pdev)); } // Handle BOT error MSC_BOT_CplClrFeature(pdev, (uint8_t)req->wIndex); @@ -1000,18 +1012,66 @@ static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t *length) { usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; + + #if USBD_SUPPORT_HS_MODE + uint8_t *cdc_desc = NULL; + uint8_t *msc_desc = NULL; + switch (usbd->usbd_mode) { + case USBD_MODE_MSC: + msc_desc = usbd->usbd_config_desc + MSC_TEMPLATE_MSC_DESC_OFFSET; + break; + + case USBD_MODE_CDC_MSC: + cdc_desc = usbd->usbd_config_desc + CDC_MSC_TEMPLATE_CDC_DESC_OFFSET; + msc_desc = usbd->usbd_config_desc + CDC_MSC_TEMPLATE_MSC_DESC_OFFSET; + break; + + case USBD_MODE_CDC_HID: + cdc_desc = usbd->usbd_config_desc + CDC_HID_TEMPLATE_CDC_DESC_OFFSET; + break; + + case USBD_MODE_CDC: + cdc_desc = usbd->usbd_config_desc + CDC_TEMPLATE_CDC_DESC_OFFSET; + break; + } + + // configure CDC descriptors, if needed + if (cdc_desc != NULL) { + uint32_t mp = usbd_cdc_max_packet(pdev); + cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_LO] = LOBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_HI] = HIBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_LO] = LOBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_HI] = HIBYTE(mp); + uint8_t interval; // polling interval in frames of 1ms + if (pdev->dev_speed == USBD_SPEED_HIGH) { + interval = 0x09; + } else { + interval = 0x20; + } + cdc_desc[CDC_DESC_OFFSET_INTR_INTERVAL] = interval; + } + + if (msc_desc != NULL) { + uint32_t mp = usbd_msc_max_packet(pdev); + msc_desc[13] = LOBYTE(mp); + msc_desc[14] = HIBYTE(mp); + msc_desc[20] = LOBYTE(mp); + msc_desc[21] = HIBYTE(mp); + } + #endif + *length = usbd->usbd_config_desc_size; return usbd->usbd_config_desc; } -// this is used only in high-speed mode, which we don't support uint8_t *USBD_CDC_MSC_HID_GetDeviceQualifierDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { - /* + #if USBD_SUPPORT_HS_MODE *length = sizeof(USBD_CDC_MSC_HID_DeviceQualifierDesc); return USBD_CDC_MSC_HID_DeviceQualifierDesc; - */ + #else *length = 0; return NULL; + #endif } // data received on non-control OUT endpoint @@ -1031,12 +1091,15 @@ uint8_t USBD_CDC_TransmitPacket(usbd_cdc_msc_hid_state_t *usbd, size_t len, cons // prepare OUT endpoint for reception uint8_t USBD_CDC_ReceivePacket(usbd_cdc_msc_hid_state_t *usbd, uint8_t *buf) { // Suspend or Resume USB Out process + + #if !USBD_SUPPORT_HS_MODE if (usbd->pdev->dev_speed == USBD_SPEED_HIGH) { return USBD_FAIL; } + #endif // Prepare Out endpoint to receive next packet - USBD_LL_PrepareReceive(usbd->pdev, CDC_OUT_EP, buf, CDC_DATA_OUT_PACKET_SIZE); + USBD_LL_PrepareReceive(usbd->pdev, CDC_OUT_EP, buf, usbd_cdc_max_packet(usbd->pdev)); return USBD_OK; } @@ -1044,9 +1107,12 @@ uint8_t USBD_CDC_ReceivePacket(usbd_cdc_msc_hid_state_t *usbd, uint8_t *buf) { // prepare OUT endpoint for reception uint8_t USBD_HID_ReceivePacket(usbd_cdc_msc_hid_state_t *usbd, uint8_t *buf) { // Suspend or Resume USB Out process + + #if !USBD_SUPPORT_HS_MODE if (usbd->pdev->dev_speed == USBD_SPEED_HIGH) { return USBD_FAIL; } + #endif // Prepare Out endpoint to receive next packet uint16_t mps_out = diff --git a/ports/stm32/usbdev/core/inc/usbd_core.h b/ports/stm32/usbdev/core/inc/usbd_core.h index 3178d4a4ba..fb1d541f6b 100644 --- a/ports/stm32/usbdev/core/inc/usbd_core.h +++ b/ports/stm32/usbdev/core/inc/usbd_core.h @@ -111,7 +111,7 @@ USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev); USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev); /* USBD Low Level Driver */ -USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev, int high_speed); USBD_StatusTypeDef USBD_LL_DeInit (USBD_HandleTypeDef *pdev); USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev); USBD_StatusTypeDef USBD_LL_Stop (USBD_HandleTypeDef *pdev); diff --git a/ports/stm32/usbdev/core/src/usbd_core.c b/ports/stm32/usbdev/core/src/usbd_core.c index ae5b99626f..23d2bc09f7 100644 --- a/ports/stm32/usbdev/core/src/usbd_core.c +++ b/ports/stm32/usbdev/core/src/usbd_core.c @@ -119,7 +119,7 @@ USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev, USBD_DescriptorsTypeDef * pdev->dev_state = USBD_STATE_DEFAULT; pdev->id = id; /* Initialize low level driver */ - USBD_LL_Init(pdev); + USBD_LL_Init(pdev, 0); return USBD_OK; } From 618aaa4a533c97b82761935c2939addf2f07ed45 Mon Sep 17 00:00:00 2001 From: liamkinne Date: Sun, 7 Jan 2018 22:40:29 +1100 Subject: [PATCH 264/828] stm32/i2c: Use macros instead of magic numbers for I2C speed grades. --- ports/stm32/i2c.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index 5a6edc3297..6cb6538cbf 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -89,6 +89,10 @@ #define PYB_I2C_MASTER (0) #define PYB_I2C_SLAVE (1) +#define PYB_I2C_SPEED_STANDARD (100000L) +#define PYB_I2C_SPEED_FULL (400000L) +#define PYB_I2C_SPEED_FAST (1000000L) + #if defined(MICROPY_HW_I2C1_SCL) I2C_HandleTypeDef I2CHandle1 = {.Instance = NULL}; #endif @@ -137,12 +141,12 @@ const pyb_i2c_obj_t pyb_i2c_obj[] = { // The value 0x40912732 was obtained from the DISCOVERY_I2Cx_TIMING constant // defined in the STM32F7Cube file Drivers/BSP/STM32F746G-Discovery/stm32f7456g_discovery.h #define MICROPY_HW_I2C_BAUDRATE_TIMING { \ - {100000, 0x40912732}, \ - {400000, 0x10911823}, \ - {1000000, 0x00611116}, \ + {PYB_I2C_SPEED_STANDARD, 0x40912732}, \ + {PYB_I2C_SPEED_FULL, 0x10911823}, \ + {PYB_I2C_SPEED_FAST, 0x00611116}, \ } -#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (400000) -#define MICROPY_HW_I2C_BAUDRATE_MAX (1000000) +#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL) +#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FAST) #elif defined(STM32F722xx) || defined(STM32F723xx) \ || defined(STM32F732xx) || defined(STM32F733xx) \ @@ -150,20 +154,20 @@ const pyb_i2c_obj_t pyb_i2c_obj[] = { // These timing values are for f_I2CCLK=54MHz and are only approximate #define MICROPY_HW_I2C_BAUDRATE_TIMING { \ - {100000, 0xb0420f13}, \ - {400000, 0x70330309}, \ - {1000000, 0x50100103}, \ + {PYB_I2C_SPEED_STANDARD, 0xb0420f13}, \ + {PYB_I2C_SPEED_FULL, 0x70330309}, \ + {PYB_I2C_SPEED_FAST, 0x50100103}, \ } -#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (400000) -#define MICROPY_HW_I2C_BAUDRATE_MAX (1000000) +#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL) +#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FAST) #elif defined(MCU_SERIES_L4) // The value 0x90112626 was obtained from the DISCOVERY_I2C1_TIMING constant // defined in the STM32L4Cube file Drivers/BSP/STM32L476G-Discovery/stm32l476g_discovery.h -#define MICROPY_HW_I2C_BAUDRATE_TIMING {{100000, 0x90112626}} -#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (100000) -#define MICROPY_HW_I2C_BAUDRATE_MAX (100000) +#define MICROPY_HW_I2C_BAUDRATE_TIMING {{PYB_I2C_SPEED_STANDARD, 0x90112626}} +#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_STANDARD) +#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_STANDARD) #else #error "no I2C timings for this MCU" @@ -198,8 +202,8 @@ uint32_t i2c_get_baudrate(I2C_InitTypeDef *init) { #else -#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (400000) -#define MICROPY_HW_I2C_BAUDRATE_MAX (400000) +#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL) +#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FULL) STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) { init->ClockSpeed = baudrate; From 762db9ad2f44dc87220b0ae1009251615d8e2e18 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Feb 2018 17:44:05 +1100 Subject: [PATCH 265/828] stm32/spi: Add support for a board naming SPI peripherals 4, 5 and 6. --- ports/stm32/spi.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c index 2b5bdb038b..2b743bdfae 100644 --- a/ports/stm32/spi.c +++ b/ports/stm32/spi.c @@ -179,6 +179,18 @@ STATIC int spi_find(mp_obj_t id) { } else if (strcmp(port, MICROPY_HW_SPI3_NAME) == 0) { return 3; #endif + #ifdef MICROPY_HW_SPI4_NAME + } else if (strcmp(port, MICROPY_HW_SPI4_NAME) == 0) { + return 4; + #endif + #ifdef MICROPY_HW_SPI5_NAME + } else if (strcmp(port, MICROPY_HW_SPI5_NAME) == 0) { + return 5; + #endif + #ifdef MICROPY_HW_SPI6_NAME + } else if (strcmp(port, MICROPY_HW_SPI6_NAME) == 0) { + return 6; + #endif } nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "SPI(%s) doesn't exist", port)); From 57d2ac130016cf8500423171cb630ec5b2f09b3a Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Feb 2018 18:22:57 +1100 Subject: [PATCH 266/828] stm32/rng: Simplify RNG implementation by accessing raw peripheral regs. It saves code size and RAM, and is more efficient to execute. --- ports/stm32/Makefile | 1 - ports/stm32/main.c | 4 ---- ports/stm32/rng.c | 47 ++++++++++++++++++-------------------------- ports/stm32/rng.h | 3 ++- 4 files changed, 21 insertions(+), 34 deletions(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 65962bea67..55ccafe766 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -265,7 +265,6 @@ SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ hal_pwr_ex.c \ hal_rcc.c \ hal_rcc_ex.c \ - hal_rng.c \ hal_rtc.c \ hal_rtc_ex.c \ hal_sd.c \ diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 352c09bcd4..60615736d3 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -552,10 +552,6 @@ soft_reset: can_init0(); #endif -#if MICROPY_HW_ENABLE_RNG - rng_init0(); -#endif - #if MICROPY_HW_ENABLE_HW_I2C i2c_init0(); #endif diff --git a/ports/stm32/rng.c b/ports/stm32/rng.c index c0c5e9aeb5..85dcc14109 100644 --- a/ports/stm32/rng.c +++ b/ports/stm32/rng.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2018 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,44 +24,35 @@ * THE SOFTWARE. */ -#include - -#include "py/obj.h" #include "rng.h" #if MICROPY_HW_ENABLE_RNG -/// \moduleref pyb - -STATIC RNG_HandleTypeDef RNGHandle = {.Instance = NULL}; - -void rng_init0(void) { - // reset the RNG handle - memset(&RNGHandle, 0, sizeof(RNG_HandleTypeDef)); - RNGHandle.Instance = RNG; -} - -void rng_init(void) { - __RNG_CLK_ENABLE(); - HAL_RNG_Init(&RNGHandle); -} +#define RNG_TIMEOUT_MS (10) uint32_t rng_get(void) { - if (RNGHandle.State == HAL_RNG_STATE_RESET) { - rng_init(); + // Enable the RNG peripheral if it's not already enabled + if (!(RNG->CR & RNG_CR_RNGEN)) { + __HAL_RCC_RNG_CLK_ENABLE(); + RNG->CR |= RNG_CR_RNGEN; } - return HAL_RNG_GetRandomNumber(&RNGHandle); + + // Wait for a new random number to be ready, takes on the order of 10us + uint32_t start = HAL_GetTick(); + while (!(RNG->SR & RNG_SR_DRDY)) { + if (HAL_GetTick() - start >= RNG_TIMEOUT_MS) { + return 0; + } + } + + // Get and return the new random number + return RNG->DR; } -/// \function rng() -/// Return a 30-bit hardware generated random number. +// Return a 30-bit hardware generated random number. STATIC mp_obj_t pyb_rng_get(void) { - if (RNGHandle.State == HAL_RNG_STATE_RESET) { - rng_init(); - } - return mp_obj_new_int(HAL_RNG_GetRandomNumber(&RNGHandle) >> 2); + return mp_obj_new_int(rng_get() >> 2); } - MP_DEFINE_CONST_FUN_OBJ_0(pyb_rng_get_obj, pyb_rng_get); #endif // MICROPY_HW_ENABLE_RNG diff --git a/ports/stm32/rng.h b/ports/stm32/rng.h index 43e49fe72e..1478b7d3f2 100644 --- a/ports/stm32/rng.h +++ b/ports/stm32/rng.h @@ -26,7 +26,8 @@ #ifndef MICROPY_INCLUDED_STMHAL_RNG_H #define MICROPY_INCLUDED_STMHAL_RNG_H -void rng_init0(void); +#include "py/obj.h" + uint32_t rng_get(void); MP_DECLARE_CONST_FUN_OBJ_0(pyb_rng_get_obj); From 5ddd1488bd5ac7a41d76e68b84ff858d7fa0aad7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Feb 2018 19:01:11 +1100 Subject: [PATCH 267/828] stm32/spi: Allow SPI peripheral state to persist across a soft reset. The SPI sub-system is independent from the uPy state (eg the heap) and so can safely persist across a soft reset. And this is actually necessary for drivers that rely on SPI and that also need to persist across soft reset (eg external SPI flash memory). --- ports/stm32/main.c | 2 +- ports/stm32/spi.c | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 60615736d3..7a530ff83a 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -457,6 +457,7 @@ int main(void) { #if MICROPY_HW_HAS_SWITCH switch_init0(); #endif + spi_init0(); #if defined(USE_DEVICE_MODE) // default to internal flash being the usb medium @@ -556,7 +557,6 @@ soft_reset: i2c_init0(); #endif - spi_init0(); pyb_usb_init0(); // Initialise the local flash filesystem. diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c index 2b743bdfae..31157d8825 100644 --- a/ports/stm32/spi.c +++ b/ports/stm32/spi.c @@ -135,29 +135,24 @@ STATIC const pyb_spi_obj_t pyb_spi_obj[] = { }; void spi_init0(void) { - // reset the SPI handles + // Initialise the SPI handles. + // The structs live on the BSS so all other fields will be zero after a reset. #if defined(MICROPY_HW_SPI1_SCK) - memset(&SPIHandle1, 0, sizeof(SPI_HandleTypeDef)); SPIHandle1.Instance = SPI1; #endif #if defined(MICROPY_HW_SPI2_SCK) - memset(&SPIHandle2, 0, sizeof(SPI_HandleTypeDef)); SPIHandle2.Instance = SPI2; #endif #if defined(MICROPY_HW_SPI3_SCK) - memset(&SPIHandle3, 0, sizeof(SPI_HandleTypeDef)); SPIHandle3.Instance = SPI3; #endif #if defined(MICROPY_HW_SPI4_SCK) - memset(&SPIHandle4, 0, sizeof(SPI_HandleTypeDef)); SPIHandle4.Instance = SPI4; #endif #if defined(MICROPY_HW_SPI5_SCK) - memset(&SPIHandle5, 0, sizeof(SPI_HandleTypeDef)); SPIHandle5.Instance = SPI5; #endif #if defined(MICROPY_HW_SPI6_SCK) - memset(&SPIHandle6, 0, sizeof(SPI_HandleTypeDef)); SPIHandle6.Instance = SPI6; #endif } From 4b8e58756bf408f4a899d7cf787ed1961f6f9682 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Feb 2018 19:04:36 +1100 Subject: [PATCH 268/828] stm32/i2c: Allow I2C peripheral state to persist across a soft reset. The I2C sub-system is independent from the uPy state (eg the heap) and so can safely persist across a soft reset. --- ports/stm32/i2c.c | 7 ++----- ports/stm32/main.c | 7 +++---- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index 6cb6538cbf..56c63684f5 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -217,21 +217,18 @@ uint32_t i2c_get_baudrate(I2C_InitTypeDef *init) { #endif void i2c_init0(void) { - // reset the I2C1 handles + // Initialise the I2C handles. + // The structs live on the BSS so all other fields will be zero after a reset. #if defined(MICROPY_HW_I2C1_SCL) - memset(&I2CHandle1, 0, sizeof(I2C_HandleTypeDef)); I2CHandle1.Instance = I2C1; #endif #if defined(MICROPY_HW_I2C2_SCL) - memset(&I2CHandle2, 0, sizeof(I2C_HandleTypeDef)); I2CHandle2.Instance = I2C2; #endif #if defined(MICROPY_HW_I2C3_SCL) - memset(&I2CHandle3, 0, sizeof(I2C_HandleTypeDef)); I2CHandle3.Instance = I2C3; #endif #if defined(MICROPY_HW_I2C4_SCL) - memset(&I2CHandle4, 0, sizeof(I2C_HandleTypeDef)); I2CHandle4.Instance = I2C4; #endif } diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 7a530ff83a..5617747e98 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -458,6 +458,9 @@ int main(void) { switch_init0(); #endif spi_init0(); + #if MICROPY_HW_ENABLE_HW_I2C + i2c_init0(); + #endif #if defined(USE_DEVICE_MODE) // default to internal flash being the usb medium @@ -553,10 +556,6 @@ soft_reset: can_init0(); #endif - #if MICROPY_HW_ENABLE_HW_I2C - i2c_init0(); - #endif - pyb_usb_init0(); // Initialise the local flash filesystem. From 253f2bd7be39e201db78960be456ac0f8c61b05f Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 4 Feb 2018 13:35:21 +1100 Subject: [PATCH 269/828] py/compile: Combine compiler-opt of 2 and 3 tuple-to-tuple assignment. This patch combines the compiler optimisation code for double and triple tuple-to-tuple assignment, taking it from two separate if-blocks to one combined if-block. This can be done because the code for both of these optimisations has a lot in common. Combining them together reduces code size for ports that have the triple-tuple optimisation enabled (and doesn't change code size for ports that have it disabled). --- py/compile.c | 85 ++++++++++++++++++++++++++------------------------- py/mpconfig.h | 2 +- 2 files changed, 44 insertions(+), 43 deletions(-) diff --git a/py/compile.c b/py/compile.c index 52d10ee5e8..42ae8a8290 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1941,51 +1941,52 @@ STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { } } else { plain_assign: - if (MICROPY_COMP_DOUBLE_TUPLE_ASSIGN - && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_testlist_star_expr) - && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr) - && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[1]) == 2 - && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[0]) == 2) { - // optimisation for a, b = c, d - mp_parse_node_struct_t *pns10 = (mp_parse_node_struct_t*)pns->nodes[1]; + #if MICROPY_COMP_DOUBLE_TUPLE_ASSIGN + if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_testlist_star_expr) + && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr)) { mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns->nodes[0]; - if (MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr) - || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[1], PN_star_expr)) { - // can't optimise when it's a star expression on the lhs - goto no_optimisation; + pns1 = (mp_parse_node_struct_t*)pns->nodes[1]; + uint32_t n_pns0 = MP_PARSE_NODE_STRUCT_NUM_NODES(pns0); + // Can only optimise a tuple-to-tuple assignment when all of the following hold: + // - equal number of items in LHS and RHS tuples + // - 2 or 3 items in the tuples + // - there are no star expressions in the LHS tuple + if (n_pns0 == MP_PARSE_NODE_STRUCT_NUM_NODES(pns1) + && (n_pns0 == 2 + #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN + || n_pns0 == 3 + #endif + ) + && !MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr) + && !MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[1], PN_star_expr) + #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN + && (n_pns0 == 2 || !MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[2], PN_star_expr)) + #endif + ) { + // Optimisation for a, b = c, d or a, b, c = d, e, f + compile_node(comp, pns1->nodes[0]); // rhs + compile_node(comp, pns1->nodes[1]); // rhs + #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN + if (n_pns0 == 3) { + compile_node(comp, pns1->nodes[2]); // rhs + EMIT(rot_three); + } + #endif + EMIT(rot_two); + c_assign(comp, pns0->nodes[0], ASSIGN_STORE); // lhs store + c_assign(comp, pns0->nodes[1], ASSIGN_STORE); // lhs store + #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN + if (n_pns0 == 3) { + c_assign(comp, pns0->nodes[2], ASSIGN_STORE); // lhs store + } + #endif + return; } - compile_node(comp, pns10->nodes[0]); // rhs - compile_node(comp, pns10->nodes[1]); // rhs - EMIT(rot_two); - c_assign(comp, pns0->nodes[0], ASSIGN_STORE); // lhs store - c_assign(comp, pns0->nodes[1], ASSIGN_STORE); // lhs store - } else if (MICROPY_COMP_TRIPLE_TUPLE_ASSIGN - && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_testlist_star_expr) - && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr) - && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[1]) == 3 - && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[0]) == 3) { - // optimisation for a, b, c = d, e, f - mp_parse_node_struct_t *pns10 = (mp_parse_node_struct_t*)pns->nodes[1]; - mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns->nodes[0]; - if (MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr) - || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[1], PN_star_expr) - || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[2], PN_star_expr)) { - // can't optimise when it's a star expression on the lhs - goto no_optimisation; - } - compile_node(comp, pns10->nodes[0]); // rhs - compile_node(comp, pns10->nodes[1]); // rhs - compile_node(comp, pns10->nodes[2]); // rhs - EMIT(rot_three); - EMIT(rot_two); - c_assign(comp, pns0->nodes[0], ASSIGN_STORE); // lhs store - c_assign(comp, pns0->nodes[1], ASSIGN_STORE); // lhs store - c_assign(comp, pns0->nodes[2], ASSIGN_STORE); // lhs store - } else { - no_optimisation: - compile_node(comp, pns->nodes[1]); // rhs - c_assign(comp, pns->nodes[0], ASSIGN_STORE); // lhs store } + #endif + + compile_node(comp, pns->nodes[1]); // rhs + c_assign(comp, pns->nodes[0], ASSIGN_STORE); // lhs store } } else { goto plain_assign; diff --git a/py/mpconfig.h b/py/mpconfig.h index 763bb378e0..f2a8c98cbb 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -347,7 +347,7 @@ #endif // Whether to enable optimisation of: a, b, c = d, e, f -// Cost 156 bytes (Thumb2) +// Requires MICROPY_COMP_DOUBLE_TUPLE_ASSIGN and costs 68 bytes (Thumb2) #ifndef MICROPY_COMP_TRIPLE_TUPLE_ASSIGN #define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0) #endif From 4ad3ede21ab2210e4ed9c61f75ed1f06080b8baf Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 5 Feb 2018 13:44:31 +1100 Subject: [PATCH 270/828] stm32/spi: Provide better separation between SPI driver and uPy objs. There is an underlying hardware SPI driver (built on top of the STM HAL) and then on top of this sits the legacy pyb.SPI class as well as the machine.SPI class. This patch improves the separation between these layers, in particular decoupling machine.SPI from pyb.SPI. --- ports/stm32/spi.c | 130 ++++++++++++++++++++++++---------------------- ports/stm32/spi.h | 15 +++++- 2 files changed, 81 insertions(+), 64 deletions(-) diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c index 31157d8825..bb35a042b1 100644 --- a/ports/stm32/spi.c +++ b/ports/stm32/spi.c @@ -34,7 +34,6 @@ #include "pin.h" #include "genhdr/pins.h" #include "bufhelper.h" -#include "dma.h" #include "spi.h" /// \moduleref pyb @@ -75,13 +74,6 @@ // SPI6_TX: DMA2_Stream5.CHANNEL_1 // SPI6_RX: DMA2_Stream6.CHANNEL_1 -typedef struct _pyb_spi_obj_t { - mp_obj_base_t base; - SPI_HandleTypeDef *spi; - const dma_descr_t *tx_dma_descr; - const dma_descr_t *rx_dma_descr; -} pyb_spi_obj_t; - #if defined(MICROPY_HW_SPI1_SCK) SPI_HandleTypeDef SPIHandle1 = {.Instance = NULL}; #endif @@ -101,36 +93,36 @@ SPI_HandleTypeDef SPIHandle5 = {.Instance = NULL}; SPI_HandleTypeDef SPIHandle6 = {.Instance = NULL}; #endif -STATIC const pyb_spi_obj_t pyb_spi_obj[] = { +const spi_t spi_obj[6] = { #if defined(MICROPY_HW_SPI1_SCK) - {{&pyb_spi_type}, &SPIHandle1, &dma_SPI_1_TX, &dma_SPI_1_RX}, + {&SPIHandle1, &dma_SPI_1_TX, &dma_SPI_1_RX}, #else - {{&pyb_spi_type}, NULL, NULL, NULL}, + {NULL, NULL, NULL}, #endif #if defined(MICROPY_HW_SPI2_SCK) - {{&pyb_spi_type}, &SPIHandle2, &dma_SPI_2_TX, &dma_SPI_2_RX}, + {&SPIHandle2, &dma_SPI_2_TX, &dma_SPI_2_RX}, #else - {{&pyb_spi_type}, NULL, NULL, NULL}, + {NULL, NULL, NULL}, #endif #if defined(MICROPY_HW_SPI3_SCK) - {{&pyb_spi_type}, &SPIHandle3, &dma_SPI_3_TX, &dma_SPI_3_RX}, + {&SPIHandle3, &dma_SPI_3_TX, &dma_SPI_3_RX}, #else - {{&pyb_spi_type}, NULL, NULL, NULL}, + {NULL, NULL, NULL}, #endif #if defined(MICROPY_HW_SPI4_SCK) - {{&pyb_spi_type}, &SPIHandle4, &dma_SPI_4_TX, &dma_SPI_4_RX}, + {&SPIHandle4, &dma_SPI_4_TX, &dma_SPI_4_RX}, #else - {{&pyb_spi_type}, NULL, NULL, NULL}, + {NULL, NULL, NULL}, #endif #if defined(MICROPY_HW_SPI5_SCK) - {{&pyb_spi_type}, &SPIHandle5, &dma_SPI_5_TX, &dma_SPI_5_RX}, + {&SPIHandle5, &dma_SPI_5_TX, &dma_SPI_5_RX}, #else - {{&pyb_spi_type}, NULL, NULL, NULL}, + {NULL, NULL, NULL}, #endif #if defined(MICROPY_HW_SPI6_SCK) - {{&pyb_spi_type}, &SPIHandle6, &dma_SPI_6_TX, &dma_SPI_6_RX}, + {&SPIHandle6, &dma_SPI_6_TX, &dma_SPI_6_RX}, #else - {{&pyb_spi_type}, NULL, NULL, NULL}, + {NULL, NULL, NULL}, #endif }; @@ -192,8 +184,8 @@ STATIC int spi_find(mp_obj_t id) { } else { // given an integer id int spi_id = mp_obj_get_int(id); - if (spi_id >= 1 && spi_id <= MP_ARRAY_SIZE(pyb_spi_obj) - && pyb_spi_obj[spi_id - 1].spi != NULL) { + if (spi_id >= 1 && spi_id <= MP_ARRAY_SIZE(spi_obj) + && spi_obj[spi_id - 1].spi != NULL) { return spi_id; } nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, @@ -203,8 +195,9 @@ STATIC int spi_find(mp_obj_t id) { // sets the parameters in the SPI_InitTypeDef struct // if an argument is -1 then the corresponding parameter is not changed -STATIC void spi_set_params(SPI_HandleTypeDef *spi, uint32_t prescale, int32_t baudrate, +STATIC void spi_set_params(const spi_t *spi_obj, uint32_t prescale, int32_t baudrate, int32_t polarity, int32_t phase, int32_t bits, int32_t firstbit) { + SPI_HandleTypeDef *spi = spi_obj->spi; SPI_InitTypeDef *init = &spi->Init; if (prescale != 0xffffffff || baudrate != -1) { @@ -248,14 +241,13 @@ STATIC void spi_set_params(SPI_HandleTypeDef *spi, uint32_t prescale, int32_t ba } // TODO allow to take a list of pins to use -void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { - const pyb_spi_obj_t *self; +void spi_init(const spi_t *self, bool enable_nss_pin) { + SPI_HandleTypeDef *spi = self->spi; const pin_obj_t *pins[4] = { NULL, NULL, NULL, NULL }; if (0) { #if defined(MICROPY_HW_SPI1_SCK) } else if (spi->Instance == SPI1) { - self = &pyb_spi_obj[0]; #if defined(MICROPY_HW_SPI1_NSS) pins[0] = &MICROPY_HW_SPI1_NSS; #endif @@ -269,7 +261,6 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { #endif #if defined(MICROPY_HW_SPI2_SCK) } else if (spi->Instance == SPI2) { - self = &pyb_spi_obj[1]; #if defined(MICROPY_HW_SPI2_NSS) pins[0] = &MICROPY_HW_SPI2_NSS; #endif @@ -283,7 +274,6 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { #endif #if defined(MICROPY_HW_SPI3_SCK) } else if (spi->Instance == SPI3) { - self = &pyb_spi_obj[2]; #if defined(MICROPY_HW_SPI3_NSS) pins[0] = &MICROPY_HW_SPI3_NSS; #endif @@ -297,7 +287,6 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { #endif #if defined(MICROPY_HW_SPI4_SCK) } else if (spi->Instance == SPI4) { - self = &pyb_spi_obj[3]; #if defined(MICROPY_HW_SPI4_NSS) pins[0] = &MICROPY_HW_SPI4_NSS; #endif @@ -311,7 +300,6 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { #endif #if defined(MICROPY_HW_SPI5_SCK) } else if (spi->Instance == SPI5) { - self = &pyb_spi_obj[4]; #if defined(MICROPY_HW_SPI5_NSS) pins[0] = &MICROPY_HW_SPI5_NSS; #endif @@ -325,7 +313,6 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { #endif #if defined(MICROPY_HW_SPI6_SCK) } else if (spi->Instance == SPI6) { - self = &pyb_spi_obj[5]; #if defined(MICROPY_HW_SPI6_NSS) pins[0] = &MICROPY_HW_SPI6_NSS; #endif @@ -349,7 +336,7 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { if (pins[i] == NULL) { continue; } - mp_hal_pin_config_alt(pins[i], mode, pull, AF_FN_SPI, (self - &pyb_spi_obj[0]) + 1); + mp_hal_pin_config_alt(pins[i], mode, pull, AF_FN_SPI, (self - &spi_obj[0]) + 1); } // init the SPI device @@ -368,7 +355,8 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { dma_invalidate_channel(self->rx_dma_descr); } -void spi_deinit(SPI_HandleTypeDef *spi) { +void spi_deinit(const spi_t *spi_obj) { + SPI_HandleTypeDef *spi = spi_obj->spi; HAL_SPI_DeInit(spi); if (0) { #if defined(MICROPY_HW_SPI1_SCK) @@ -410,12 +398,13 @@ void spi_deinit(SPI_HandleTypeDef *spi) { } } -STATIC HAL_StatusTypeDef spi_wait_dma_finished(SPI_HandleTypeDef *spi, uint32_t timeout) { +STATIC HAL_StatusTypeDef spi_wait_dma_finished(const spi_t *spi, uint32_t timeout) { uint32_t start = HAL_GetTick(); + volatile HAL_SPI_StateTypeDef *state = &spi->spi->State; for (;;) { // Do an atomic check of the state; WFI will exit even if IRQs are disabled uint32_t irq_state = disable_irq(); - if (spi->State == HAL_SPI_STATE_READY) { + if (*state == HAL_SPI_STATE_READY) { enable_irq(irq_state); return HAL_OK; } @@ -433,7 +422,7 @@ STATIC HAL_StatusTypeDef spi_wait_dma_finished(SPI_HandleTypeDef *spi, uint32_t // and use that value for the baudrate in the formula, plus a small constant. #define SPI_TRANSFER_TIMEOUT(len) ((len) + 100) -STATIC void spi_transfer(const pyb_spi_obj_t *self, size_t len, const uint8_t *src, uint8_t *dest, uint32_t timeout) { +STATIC void spi_transfer(const spi_t *self, size_t len, const uint8_t *src, uint8_t *dest, uint32_t timeout) { // Note: there seems to be a problem sending 1 byte using DMA the first // time directly after the SPI/DMA is initialised. The cause of this is // unknown but we sidestep the issue by using polling for 1 byte transfer. @@ -452,7 +441,7 @@ STATIC void spi_transfer(const pyb_spi_obj_t *self, size_t len, const uint8_t *s MP_HAL_CLEAN_DCACHE(src, len); status = HAL_SPI_Transmit_DMA(self->spi, (uint8_t*)src, len); if (status == HAL_OK) { - status = spi_wait_dma_finished(self->spi, timeout); + status = spi_wait_dma_finished(self, timeout); } dma_deinit(self->tx_dma_descr); } @@ -474,7 +463,7 @@ STATIC void spi_transfer(const pyb_spi_obj_t *self, size_t len, const uint8_t *s MP_HAL_CLEANINVALIDATE_DCACHE(dest, len); status = HAL_SPI_Receive_DMA(self->spi, dest, len); if (status == HAL_OK) { - status = spi_wait_dma_finished(self->spi, timeout); + status = spi_wait_dma_finished(self, timeout); } if (self->spi->hdmatx != NULL) { dma_deinit(self->tx_dma_descr); @@ -495,7 +484,7 @@ STATIC void spi_transfer(const pyb_spi_obj_t *self, size_t len, const uint8_t *s MP_HAL_CLEANINVALIDATE_DCACHE(dest, len); status = HAL_SPI_TransmitReceive_DMA(self->spi, (uint8_t*)src, dest, len); if (status == HAL_OK) { - status = spi_wait_dma_finished(self->spi, timeout); + status = spi_wait_dma_finished(self, timeout); } dma_deinit(self->tx_dma_descr); dma_deinit(self->rx_dma_descr); @@ -507,7 +496,9 @@ STATIC void spi_transfer(const pyb_spi_obj_t *self, size_t len, const uint8_t *s } } -STATIC void spi_print(const mp_print_t *print, SPI_HandleTypeDef *spi, bool legacy) { +STATIC void spi_print(const mp_print_t *print, const spi_t *spi_obj, bool legacy) { + SPI_HandleTypeDef *spi = spi_obj->spi; + uint spi_num = 1; // default to SPI1 if (spi->Instance == SPI2) { spi_num = 2; } else if (spi->Instance == SPI3) { spi_num = 3; } @@ -556,7 +547,21 @@ STATIC void spi_print(const mp_print_t *print, SPI_HandleTypeDef *spi, bool lega /******************************************************************************/ /* MicroPython bindings for legacy pyb API */ -SPI_HandleTypeDef *spi_get_handle(mp_obj_t o) { +typedef struct _pyb_spi_obj_t { + mp_obj_base_t base; + const spi_t *spi; +} pyb_spi_obj_t; + +STATIC const pyb_spi_obj_t pyb_spi_obj[] = { + {{&pyb_spi_type}, &spi_obj[0]}, + {{&pyb_spi_type}, &spi_obj[1]}, + {{&pyb_spi_type}, &spi_obj[2]}, + {{&pyb_spi_type}, &spi_obj[3]}, + {{&pyb_spi_type}, &spi_obj[4]}, + {{&pyb_spi_type}, &spi_obj[5]}, +}; + +const spi_t *spi_from_mp_obj(mp_obj_t o) { if (!MP_OBJ_IS_TYPE(o, &pyb_spi_type)) { mp_raise_ValueError("expecting an SPI object"); } @@ -595,7 +600,7 @@ STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_obj_t *self, size_t n_args, co mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); // set the SPI configuration values - SPI_InitTypeDef *init = &self->spi->Init; + SPI_InitTypeDef *init = &self->spi->spi->Init; init->Mode = args[0].u_int; spi_set_params(self->spi, args[2].u_int, args[1].u_int, args[3].u_int, args[4].u_int, @@ -693,7 +698,7 @@ STATIC mp_obj_t pyb_spi_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t * pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data); // send the data - spi_transfer(self, bufinfo.len, bufinfo.buf, NULL, args[1].u_int); + spi_transfer(self->spi, bufinfo.len, bufinfo.buf, NULL, args[1].u_int); return mp_const_none; } @@ -727,7 +732,7 @@ STATIC mp_obj_t pyb_spi_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t * mp_obj_t o_ret = pyb_buf_get_for_recv(args[0].u_obj, &vstr); // receive the data - spi_transfer(self, vstr.len, NULL, (uint8_t*)vstr.buf, args[1].u_int); + spi_transfer(self->spi, vstr.len, NULL, (uint8_t*)vstr.buf, args[1].u_int); // return the received data if (o_ret != MP_OBJ_NULL) { @@ -797,7 +802,7 @@ STATIC mp_obj_t pyb_spi_send_recv(size_t n_args, const mp_obj_t *pos_args, mp_ma } // do the transfer - spi_transfer(self, bufinfo_send.len, bufinfo_send.buf, bufinfo_recv.buf, args[2].u_int); + spi_transfer(self->spi, bufinfo_send.len, bufinfo_send.buf, bufinfo_recv.buf, args[2].u_int); // return the received data if (o_ret != MP_OBJ_NULL) { @@ -845,7 +850,8 @@ STATIC const mp_rom_map_elem_t pyb_spi_locals_dict_table[] = { STATIC MP_DEFINE_CONST_DICT(pyb_spi_locals_dict, pyb_spi_locals_dict_table); STATIC void spi_transfer_machine(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { - spi_transfer((pyb_spi_obj_t*)self_in, len, src, dest, SPI_TRANSFER_TIMEOUT(len)); + pyb_spi_obj_t *self = (pyb_spi_obj_t*)self_in; + spi_transfer(self->spi, len, src, dest, SPI_TRANSFER_TIMEOUT(len)); } STATIC const mp_machine_spi_p_t pyb_spi_p = { @@ -866,21 +872,21 @@ const mp_obj_type_t pyb_spi_type = { typedef struct _machine_hard_spi_obj_t { mp_obj_base_t base; - const pyb_spi_obj_t *pyb; + const spi_t *spi; } machine_hard_spi_obj_t; STATIC const machine_hard_spi_obj_t machine_hard_spi_obj[] = { - {{&machine_hard_spi_type}, &pyb_spi_obj[0]}, - {{&machine_hard_spi_type}, &pyb_spi_obj[1]}, - {{&machine_hard_spi_type}, &pyb_spi_obj[2]}, - {{&machine_hard_spi_type}, &pyb_spi_obj[3]}, - {{&machine_hard_spi_type}, &pyb_spi_obj[4]}, - {{&machine_hard_spi_type}, &pyb_spi_obj[5]}, + {{&machine_hard_spi_type}, &spi_obj[0]}, + {{&machine_hard_spi_type}, &spi_obj[1]}, + {{&machine_hard_spi_type}, &spi_obj[2]}, + {{&machine_hard_spi_type}, &spi_obj[3]}, + {{&machine_hard_spi_type}, &spi_obj[4]}, + {{&machine_hard_spi_type}, &spi_obj[5]}, }; STATIC void machine_hard_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t*)self_in; - spi_print(print, self->pyb->spi, false); + spi_print(print, self->spi, false); } mp_obj_t machine_hard_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { @@ -911,7 +917,7 @@ mp_obj_t machine_hard_spi_make_new(const mp_obj_type_t *type, size_t n_args, siz } // set the SPI configuration values - SPI_InitTypeDef *init = &self->pyb->spi->Init; + SPI_InitTypeDef *init = &self->spi->spi->Init; init->Mode = SPI_MODE_MASTER; // these parameters are not currently configurable @@ -922,12 +928,12 @@ mp_obj_t machine_hard_spi_make_new(const mp_obj_type_t *type, size_t n_args, siz init->CRCPolynomial = 0; // set configurable paramaters - spi_set_params(self->pyb->spi, 0xffffffff, args[ARG_baudrate].u_int, + spi_set_params(self->spi, 0xffffffff, args[ARG_baudrate].u_int, args[ARG_polarity].u_int, args[ARG_phase].u_int, args[ARG_bits].u_int, args[ARG_firstbit].u_int); // init the SPI bus - spi_init(self->pyb->spi, false); + spi_init(self->spi, false); return MP_OBJ_FROM_PTR(self); } @@ -947,22 +953,22 @@ STATIC void machine_hard_spi_init(mp_obj_base_t *self_in, size_t n_args, const m mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); // set the SPI configuration values - spi_set_params(self->pyb->spi, 0xffffffff, args[ARG_baudrate].u_int, + spi_set_params(self->spi, 0xffffffff, args[ARG_baudrate].u_int, args[ARG_polarity].u_int, args[ARG_phase].u_int, args[ARG_bits].u_int, args[ARG_firstbit].u_int); // re-init the SPI bus - spi_init(self->pyb->spi, false); + spi_init(self->spi, false); } STATIC void machine_hard_spi_deinit(mp_obj_base_t *self_in) { machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t*)self_in; - spi_deinit(self->pyb->spi); + spi_deinit(self->spi); } STATIC void machine_hard_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t*)self_in; - spi_transfer(self->pyb, len, src, dest, SPI_TRANSFER_TIMEOUT(len)); + spi_transfer(self->spi, len, src, dest, SPI_TRANSFER_TIMEOUT(len)); } STATIC const mp_machine_spi_p_t machine_hard_spi_p = { diff --git a/ports/stm32/spi.h b/ports/stm32/spi.h index eda109a7ef..fb05703bca 100644 --- a/ports/stm32/spi.h +++ b/ports/stm32/spi.h @@ -26,18 +26,29 @@ #ifndef MICROPY_INCLUDED_STMHAL_SPI_H #define MICROPY_INCLUDED_STMHAL_SPI_H +#include "dma.h" + +typedef struct _spi_t { + SPI_HandleTypeDef *spi; + const dma_descr_t *tx_dma_descr; + const dma_descr_t *rx_dma_descr; +} spi_t; + extern SPI_HandleTypeDef SPIHandle1; extern SPI_HandleTypeDef SPIHandle2; extern SPI_HandleTypeDef SPIHandle3; extern SPI_HandleTypeDef SPIHandle4; extern SPI_HandleTypeDef SPIHandle5; extern SPI_HandleTypeDef SPIHandle6; + +extern const spi_t spi_obj[6]; + extern const mp_obj_type_t pyb_spi_type; extern const mp_obj_type_t machine_soft_spi_type; extern const mp_obj_type_t machine_hard_spi_type; void spi_init0(void); -void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin); -SPI_HandleTypeDef *spi_get_handle(mp_obj_t o); +void spi_init(const spi_t *spi, bool enable_nss_pin); +const spi_t *spi_from_mp_obj(mp_obj_t o); #endif // MICROPY_INCLUDED_STMHAL_SPI_H From f8922627d373dea850a923c54b1c23969129d705 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 5 Feb 2018 13:45:08 +1100 Subject: [PATCH 271/828] stm32: Update LCD and network drivers to work with new SPI API. --- ports/stm32/lcd.c | 12 ++++++------ ports/stm32/modnwcc3k.c | 2 +- ports/stm32/modnwwiznet5k.c | 31 ++++++++++++++++--------------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/ports/stm32/lcd.c b/ports/stm32/lcd.c index 488df1699c..62a95c0700 100644 --- a/ports/stm32/lcd.c +++ b/ports/stm32/lcd.c @@ -89,7 +89,7 @@ typedef struct _pyb_lcd_obj_t { mp_obj_base_t base; // hardware control for the LCD - SPI_HandleTypeDef *spi; + const spi_t *spi; const pin_obj_t *pin_cs1; const pin_obj_t *pin_rst; const pin_obj_t *pin_a0; @@ -119,7 +119,7 @@ STATIC void lcd_out(pyb_lcd_obj_t *lcd, int instr_data, uint8_t i) { mp_hal_pin_high(lcd->pin_a0); // A0=1; select data reg } lcd_delay(); - HAL_SPI_Transmit(lcd->spi, &i, 1, 1000); + HAL_SPI_Transmit(lcd->spi->spi, &i, 1, 1000); lcd_delay(); mp_hal_pin_high(lcd->pin_cs1); // CS=1; disable } @@ -207,13 +207,13 @@ STATIC mp_obj_t pyb_lcd_make_new(const mp_obj_type_t *type, size_t n_args, size_ // configure pins // TODO accept an SPI object and pin objects for full customisation if ((lcd_id[0] | 0x20) == 'x' && lcd_id[1] == '\0') { - lcd->spi = &SPIHandle1; + lcd->spi = &spi_obj[0]; lcd->pin_cs1 = &pyb_pin_X3; lcd->pin_rst = &pyb_pin_X4; lcd->pin_a0 = &pyb_pin_X5; lcd->pin_bl = &pyb_pin_X12; } else if ((lcd_id[0] | 0x20) == 'y' && lcd_id[1] == '\0') { - lcd->spi = &SPIHandle2; + lcd->spi = &spi_obj[1]; lcd->pin_cs1 = &pyb_pin_Y3; lcd->pin_rst = &pyb_pin_Y4; lcd->pin_a0 = &pyb_pin_Y5; @@ -223,13 +223,13 @@ STATIC mp_obj_t pyb_lcd_make_new(const mp_obj_type_t *type, size_t n_args, size_ } // init the SPI bus - SPI_InitTypeDef *init = &lcd->spi->Init; + SPI_InitTypeDef *init = &lcd->spi->spi->Init; init->Mode = SPI_MODE_MASTER; // compute the baudrate prescaler from the desired baudrate // select a prescaler that yields at most the desired baudrate uint spi_clock; - if (lcd->spi->Instance == SPI1) { + if (lcd->spi->spi->Instance == SPI1) { // SPI1 is on APB2 spi_clock = HAL_RCC_GetPCLK2Freq(); } else { diff --git a/ports/stm32/modnwcc3k.c b/ports/stm32/modnwcc3k.c index 4f1af7354c..52787187b0 100644 --- a/ports/stm32/modnwcc3k.c +++ b/ports/stm32/modnwcc3k.c @@ -433,7 +433,7 @@ STATIC mp_obj_t cc3k_make_new(const mp_obj_type_t *type, size_t n_args, size_t n // set the pins to use SpiInit( - spi_get_handle(args[0]), + spi_from_mp_obj(args[0])->spi, pin_find(args[1]), pin_find(args[2]), pin_find(args[3]) diff --git a/ports/stm32/modnwwiznet5k.c b/ports/stm32/modnwwiznet5k.c index 763137c703..2fd85531f9 100644 --- a/ports/stm32/modnwwiznet5k.c +++ b/ports/stm32/modnwwiznet5k.c @@ -48,7 +48,7 @@ typedef struct _wiznet5k_obj_t { mp_obj_base_t base; mp_uint_t cris_state; - SPI_HandleTypeDef *spi; + const spi_t *spi; const pin_obj_t *cs; const pin_obj_t *rst; uint8_t socket_used; @@ -73,12 +73,12 @@ STATIC void wiz_cs_deselect(void) { } STATIC void wiz_spi_read(uint8_t *buf, uint32_t len) { - HAL_StatusTypeDef status = HAL_SPI_Receive(wiznet5k_obj.spi, buf, len, 5000); + HAL_StatusTypeDef status = HAL_SPI_Receive(wiznet5k_obj.spi->spi, buf, len, 5000); (void)status; } STATIC void wiz_spi_write(const uint8_t *buf, uint32_t len) { - HAL_StatusTypeDef status = HAL_SPI_Transmit(wiznet5k_obj.spi, (uint8_t*)buf, len, 5000); + HAL_StatusTypeDef status = HAL_SPI_Transmit(wiznet5k_obj.spi->spi, (uint8_t*)buf, len, 5000); (void)status; } @@ -345,23 +345,24 @@ STATIC mp_obj_t wiznet5k_make_new(const mp_obj_type_t *type, size_t n_args, size // init the wiznet5k object wiznet5k_obj.base.type = (mp_obj_type_t*)&mod_network_nic_type_wiznet5k; wiznet5k_obj.cris_state = 0; - wiznet5k_obj.spi = spi_get_handle(args[0]); + wiznet5k_obj.spi = spi_from_mp_obj(args[0]); wiznet5k_obj.cs = pin_find(args[1]); wiznet5k_obj.rst = pin_find(args[2]); wiznet5k_obj.socket_used = 0; /*!< SPI configuration */ - wiznet5k_obj.spi->Init.Mode = SPI_MODE_MASTER; - wiznet5k_obj.spi->Init.Direction = SPI_DIRECTION_2LINES; - wiznet5k_obj.spi->Init.DataSize = SPI_DATASIZE_8BIT; - wiznet5k_obj.spi->Init.CLKPolarity = SPI_POLARITY_LOW; // clock is low when idle - wiznet5k_obj.spi->Init.CLKPhase = SPI_PHASE_1EDGE; // data latched on first edge, which is rising edge for low-idle - wiznet5k_obj.spi->Init.NSS = SPI_NSS_SOFT; - wiznet5k_obj.spi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; // clock freq = f_PCLK / this_prescale_value; Wiz820i can do up to 80MHz - wiznet5k_obj.spi->Init.FirstBit = SPI_FIRSTBIT_MSB; - wiznet5k_obj.spi->Init.TIMode = SPI_TIMODE_DISABLED; - wiznet5k_obj.spi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED; - wiznet5k_obj.spi->Init.CRCPolynomial = 7; // unused + SPI_InitTypeDef *init = &wiznet5k_obj.spi->spi->Init; + init->Mode = SPI_MODE_MASTER; + init->Direction = SPI_DIRECTION_2LINES; + init->DataSize = SPI_DATASIZE_8BIT; + init->CLKPolarity = SPI_POLARITY_LOW; // clock is low when idle + init->CLKPhase = SPI_PHASE_1EDGE; // data latched on first edge, which is rising edge for low-idle + init->NSS = SPI_NSS_SOFT; + init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; // clock freq = f_PCLK / this_prescale_value; Wiz820i can do up to 80MHz + init->FirstBit = SPI_FIRSTBIT_MSB; + init->TIMode = SPI_TIMODE_DISABLED; + init->CRCCalculation = SPI_CRCCALCULATION_DISABLED; + init->CRCPolynomial = 7; // unused spi_init(wiznet5k_obj.spi, false); mp_hal_pin_output(wiznet5k_obj.cs); From 93d5c9e1c4cb2850dc04abc0fa78e9b4c159747c Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 5 Feb 2018 13:45:50 +1100 Subject: [PATCH 272/828] drivers/cc3200: Update to work with new stm32 SPI API. --- drivers/cc3000/src/ccspi.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/drivers/cc3000/src/ccspi.c b/drivers/cc3000/src/ccspi.c index 820be809b3..1dcd618840 100644 --- a/drivers/cc3000/src/ccspi.c +++ b/drivers/cc3000/src/ccspi.c @@ -50,7 +50,7 @@ #endif // these need to be set to valid values before anything in this file will work -STATIC SPI_HandleTypeDef *SPI_HANDLE = NULL; +STATIC const spi_t *SPI_HANDLE = NULL; STATIC const pin_obj_t *PIN_CS = NULL; STATIC const pin_obj_t *PIN_EN = NULL; STATIC const pin_obj_t *PIN_IRQ = NULL; @@ -134,17 +134,18 @@ void SpiOpen(gcSpiHandleRx pfRxHandler) wlan_tx_buffer[CC3000_TX_BUFFER_SIZE - 1] = CC3000_BUFFER_MAGIC_NUMBER; /* SPI configuration */ - SPI_HANDLE->Init.Mode = SPI_MODE_MASTER; - SPI_HANDLE->Init.Direction = SPI_DIRECTION_2LINES; - SPI_HANDLE->Init.DataSize = SPI_DATASIZE_8BIT; - SPI_HANDLE->Init.CLKPolarity = SPI_POLARITY_LOW; - SPI_HANDLE->Init.CLKPhase = SPI_PHASE_2EDGE; - SPI_HANDLE->Init.NSS = SPI_NSS_SOFT; - SPI_HANDLE->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; - SPI_HANDLE->Init.FirstBit = SPI_FIRSTBIT_MSB; - SPI_HANDLE->Init.TIMode = SPI_TIMODE_DISABLED; - SPI_HANDLE->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED; - SPI_HANDLE->Init.CRCPolynomial = 7; + SPI_InitTypeDef *init = &SPI_HANDLE->spi->Init; + init->Mode = SPI_MODE_MASTER; + init->Direction = SPI_DIRECTION_2LINES; + init->DataSize = SPI_DATASIZE_8BIT; + init->CLKPolarity = SPI_POLARITY_LOW; + init->CLKPhase = SPI_PHASE_2EDGE; + init->NSS = SPI_NSS_SOFT; + init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; + init->FirstBit = SPI_FIRSTBIT_MSB; + init->TIMode = SPI_TIMODE_DISABLED; + init->CRCCalculation = SPI_CRCCALCULATION_DISABLED; + init->CRCPolynomial = 7; spi_init(SPI_HANDLE, false); // configure wlan CS and EN pins @@ -167,7 +168,7 @@ void SpiOpen(gcSpiHandleRx pfRxHandler) actual communications start, it might be required */ CS_LOW(); uint8_t buf[1]; - HAL_SPI_Receive(SPI_HANDLE, buf, sizeof(buf), SPI_TIMEOUT); + HAL_SPI_Receive(SPI_HANDLE->spi, buf, sizeof(buf), SPI_TIMEOUT); CS_HIGH(); // register EXTI @@ -192,7 +193,7 @@ STATIC void SpiWriteDataSynchronous(unsigned char *data, unsigned short size) { DEBUG_printf("SpiWriteDataSynchronous(data=%p [%x %x %x %x], size=%u)\n", data, data[0], data[1], data[2], data[3], size); __disable_irq(); - if (HAL_SPI_TransmitReceive(SPI_HANDLE, data, data, size, SPI_TIMEOUT) != HAL_OK) { + if (HAL_SPI_TransmitReceive(SPI_HANDLE->spi, data, data, size, SPI_TIMEOUT) != HAL_OK) { //BREAK(); } __enable_irq(); @@ -203,7 +204,7 @@ STATIC void SpiReadDataSynchronous(unsigned char *data, unsigned short size) { memset(data, READ, size); __disable_irq(); - if (HAL_SPI_TransmitReceive(SPI_HANDLE, data, data, size, SPI_TIMEOUT) != HAL_OK) { + if (HAL_SPI_TransmitReceive(SPI_HANDLE->spi, data, data, size, SPI_TIMEOUT) != HAL_OK) { //BREAK(); } __enable_irq(); From 20f5de9b397e9b9dac7070598685f24e8e9636a2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 5 Feb 2018 13:51:27 +1100 Subject: [PATCH 273/828] stm32/spi: Accept machine.SPI object in spi_from_mp_obj() function. Also, change ValueError to TypeError if the argument to this function is not of an SPI type. --- ports/stm32/spi.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c index bb35a042b1..48df9288e4 100644 --- a/ports/stm32/spi.c +++ b/ports/stm32/spi.c @@ -561,14 +561,6 @@ STATIC const pyb_spi_obj_t pyb_spi_obj[] = { {{&pyb_spi_type}, &spi_obj[5]}, }; -const spi_t *spi_from_mp_obj(mp_obj_t o) { - if (!MP_OBJ_IS_TYPE(o, &pyb_spi_type)) { - mp_raise_ValueError("expecting an SPI object"); - } - pyb_spi_obj_t *self = o; - return self->spi; -} - STATIC void pyb_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { pyb_spi_obj_t *self = self_in; spi_print(print, self->spi, true); @@ -985,3 +977,15 @@ const mp_obj_type_t machine_hard_spi_type = { .protocol = &machine_hard_spi_p, .locals_dict = (mp_obj_t)&mp_machine_spi_locals_dict, }; + +const spi_t *spi_from_mp_obj(mp_obj_t o) { + if (MP_OBJ_IS_TYPE(o, &pyb_spi_type)) { + pyb_spi_obj_t *self = o; + return self->spi; + } else if (MP_OBJ_IS_TYPE(o, &machine_hard_spi_type)) { + machine_hard_spi_obj_t *self = o;; + return self->spi; + } else { + mp_raise_TypeError("expecting an SPI object"); + } +} From 5a62f0faa62751af94a795428eddab43f7e60518 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 5 Feb 2018 14:40:06 +1100 Subject: [PATCH 274/828] stm32/rtc: Fix rtc_info flags when LSE fails and falls back to LSI. Previously, if LSE is selected but fails and the RTC falls back to LSI, then the rtc_info flags would incorrectly state that LSE is used. This patch fixes that by setting the bit in rtc_info only after the clock is ready. --- ports/stm32/rtc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index 73272d3631..029da5fc05 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -162,7 +162,7 @@ void rtc_init_finalise() { return; } - rtc_info = 0x20000000 | (rtc_use_lse << 28); + rtc_info = 0x20000000; if (PYB_RTC_Init(&RTCHandle) != HAL_OK) { if (rtc_use_lse) { // fall back to LSI... @@ -182,6 +182,9 @@ void rtc_init_finalise() { } } + // record if LSE or LSI is used + rtc_info |= (rtc_use_lse << 28); + // record how long it took for the RTC to start up rtc_info |= (HAL_GetTick() - rtc_startup_tick) & 0xffff; From 011d1555cb12d23b68085671d903f22bac331942 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 5 Feb 2018 15:12:22 +1100 Subject: [PATCH 275/828] stm32/rtc: Fix RTC init to use LSI if LSI is already selected on boot. Upon boot the RTC early-init function should detect if LSE or LSI is already selected/running and, if so, use it. When the LSI has previously (in the previous reset cycle) been selected as the clock source the only way to reliably tell is if the RTCSEL bits of the RCC_BDCR are set to the correct LSI value. In particular the RCC_CSR bits for LSI control do not indicate if the LSI is ready even if it is selected. This patch removes the check on the RCC_CSR bits for the LSI being on and ready and only uses the check on the RCC_BDCR to see if the LSI should be used straightaway. This was tested on a PYBLITEv1.0 and with the patch the LSI persists correctly as the RTC source as long as the backup domain remains powered. --- ports/stm32/rtc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index 029da5fc05..de49889949 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -132,13 +132,14 @@ void rtc_init_start(bool force_init) { // provide some status information rtc_info |= 0x40000 | (RCC->BDCR & 7) | (RCC->CSR & 3) << 8; return; - } else if (((RCC->BDCR & RCC_BDCR_RTCSEL) == RCC_BDCR_RTCSEL_1) && ((RCC->CSR & 3) == 3)) { - // LSI configured & enabled & ready --> no need to (re-)init RTC + } else if ((RCC->BDCR & RCC_BDCR_RTCSEL) == RCC_BDCR_RTCSEL_1) { + // LSI configured as the RTC clock source --> no need to (re-)init RTC // remove Backup Domain write protection HAL_PWR_EnableBkUpAccess(); // Clear source Reset Flag __HAL_RCC_CLEAR_RESET_FLAGS(); - RCC->CSR |= 1; + // Turn the LSI on (it may need this even if the RTC is running) + RCC->CSR |= RCC_CSR_LSION; // provide some status information rtc_info |= 0x80000 | (RCC->BDCR & 7) | (RCC->CSR & 3) << 8; return; From 12464f1bd2c63af012d1ce47c79f9afbfefd71e2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 5 Feb 2018 15:22:15 +1100 Subject: [PATCH 276/828] stm32/rtc: Add compile-time option to set RTC source as LSE bypass. To use the LSE bypass feature (where an external source provides the RTC clock) a board must set the config variable MICROPY_HW_RTC_USE_BYPASS. --- ports/stm32/rtc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index de49889949..fa4a3d40c1 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -335,7 +335,11 @@ STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse) { RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (rtc_use_lse) { + #if MICROPY_HW_RTC_USE_BYPASS + RCC_OscInitStruct.LSEState = RCC_LSE_BYPASS; + #else RCC_OscInitStruct.LSEState = RCC_LSE_ON; + #endif RCC_OscInitStruct.LSIState = RCC_LSI_OFF; } else { RCC_OscInitStruct.LSEState = RCC_LSE_OFF; From 4607be3768b0f6fd187fb7f17545ec3a7d28b94c Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 5 Feb 2018 15:48:28 +1100 Subject: [PATCH 277/828] stm32/main: Reorder some init calls to put them before soft-reset loop. The calls to rtc_init_start(), sdcard_init() and storage_init() are all guarded by a check for first_soft_reset, so it's simpler to just put them all before the soft-reset loop, without the check. The call to machine_init() can also go before the soft-reset loop because it is only needed to check the reset cause which can happen once at the first boot. To allow this to work, the reset cause must be set to SOFT upon a soft-reset, which is the role of the new function machine_deinit(). --- ports/stm32/main.c | 31 +++++++++++-------------------- ports/stm32/modmachine.c | 5 +++++ ports/stm32/modmachine.h | 1 + 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 5617747e98..1f39b9b9cf 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -454,13 +454,21 @@ int main(void) { #endif pendsv_init(); led_init(); -#if MICROPY_HW_HAS_SWITCH + #if MICROPY_HW_HAS_SWITCH switch_init0(); -#endif + #endif + machine_init(); + #if MICROPY_HW_ENABLE_RTC + rtc_init_start(false); + #endif spi_init0(); #if MICROPY_HW_ENABLE_HW_I2C i2c_init0(); #endif + #if MICROPY_HW_HAS_SDCARD + sdcard_init(); + #endif + storage_init(); #if defined(USE_DEVICE_MODE) // default to internal flash being the usb medium @@ -483,24 +491,6 @@ soft_reset: led_state(4, 0); uint reset_mode = update_reset_mode(1); - machine_init(); - -#if MICROPY_HW_ENABLE_RTC - if (first_soft_reset) { - rtc_init_start(false); - } -#endif - - // more sub-system init -#if MICROPY_HW_HAS_SDCARD - if (first_soft_reset) { - sdcard_init(); - } -#endif - if (first_soft_reset) { - storage_init(); - } - // Python threading init #if MICROPY_PY_THREAD mp_thread_init(); @@ -692,6 +682,7 @@ soft_reset_exit: #if MICROPY_HW_ENABLE_CAN can_deinit(); #endif + machine_deinit(); #if MICROPY_PY_THREAD pyb_thread_deinit(); diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index fba27a3bb2..3645fe60e7 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -99,6 +99,11 @@ void machine_init(void) { RCC->CSR |= RCC_CSR_RMVF; } +void machine_deinit(void) { + // we are doing a soft-reset so change the reset_cause + reset_cause = PYB_RESET_SOFT; +} + // machine.info([dump_alloc_table]) // Print out lots of information about the board. STATIC mp_obj_t machine_info(size_t n_args, const mp_obj_t *args) { diff --git a/ports/stm32/modmachine.h b/ports/stm32/modmachine.h index 77668695fc..81c6375c7e 100644 --- a/ports/stm32/modmachine.h +++ b/ports/stm32/modmachine.h @@ -29,6 +29,7 @@ #include "py/obj.h" void machine_init(void); +void machine_deinit(void); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj); MP_DECLARE_CONST_FUN_OBJ_0(machine_unique_id_obj); From cc92c0572e2b6dba3c5897d5778704aaccbb567e Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 5 Feb 2018 16:13:05 +1100 Subject: [PATCH 278/828] stm32/main: Remove need for first_soft_reset variable. --- ports/stm32/main.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 1f39b9b9cf..9d568675e3 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -263,7 +263,7 @@ MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { } #if MICROPY_HW_HAS_SDCARD -STATIC bool init_sdcard_fs(bool first_soft_reset) { +STATIC bool init_sdcard_fs(void) { bool first_part = true; for (int part_num = 1; part_num <= 4; ++part_num) { // create vfs object @@ -308,12 +308,12 @@ STATIC bool init_sdcard_fs(bool first_soft_reset) { } } - if (first_soft_reset) { - // use SD card as medium for the USB MSD - #if defined(USE_DEVICE_MODE) + #if defined(USE_DEVICE_MODE) + if (pyb_usb_storage_medium == PYB_USB_STORAGE_MEDIUM_NONE) { + // if no USB MSC medium is selected then use the SD card pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_SDCARD; - #endif } + #endif #if defined(USE_DEVICE_MODE) // only use SD card as current directory if that's what the USB medium is @@ -470,13 +470,6 @@ int main(void) { #endif storage_init(); -#if defined(USE_DEVICE_MODE) - // default to internal flash being the usb medium - pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_FLASH; -#endif - - int first_soft_reset = true; - soft_reset: // check if user switch held to select the reset mode @@ -558,11 +551,18 @@ soft_reset: if (sdcard_is_present()) { // if there is a file in the flash called "SKIPSD", then we don't mount the SD card if (!mounted_flash || f_stat(&fs_user_mount_flash.fatfs, "/SKIPSD", NULL) != FR_OK) { - mounted_sdcard = init_sdcard_fs(first_soft_reset); + mounted_sdcard = init_sdcard_fs(); } } #endif + #if defined(USE_DEVICE_MODE) + // if the SD card isn't used as the USB MSC medium then use the internal flash + if (pyb_usb_storage_medium == PYB_USB_STORAGE_MEDIUM_NONE) { + pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_FLASH; + } + #endif + // set sys.path based on mounted filesystems (/sd is first so it can override /flash) if (mounted_sdcard) { mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd)); @@ -688,6 +688,5 @@ soft_reset_exit: pyb_thread_deinit(); #endif - first_soft_reset = false; goto soft_reset; } From b45c8c17f0f295e919a90659d4c1880a47b228c1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 7 Feb 2018 15:44:29 +1100 Subject: [PATCH 279/828] py/objtype: Check and prevent delete/store on a fixed locals map. Note that the check for elem!=NULL is removed for the MP_MAP_LOOKUP_ADD_IF_NOT_FOUND case because mp_map_lookup will always return non-NULL for such a case. --- py/objtype.c | 12 ++++++------ tests/basics/del_attr.py | 7 +++++++ tests/basics/setattr1.py | 7 +++++++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/py/objtype.c b/py/objtype.c index 33757287ac..7df349ce9b 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -975,21 +975,21 @@ STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (self->locals_dict != NULL) { assert(self->locals_dict->base.type == &mp_type_dict); // MicroPython restriction, for now mp_map_t *locals_map = &self->locals_dict->map; + if (locals_map->is_fixed) { + // can't apply delete/store to a fixed map + return; + } if (dest[1] == MP_OBJ_NULL) { // delete attribute mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND); - // note that locals_map may be in ROM, so remove will fail in that case if (elem != NULL) { dest[0] = MP_OBJ_NULL; // indicate success } } else { // store attribute mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); - // note that locals_map may be in ROM, so add will fail in that case - if (elem != NULL) { - elem->value = dest[1]; - dest[0] = MP_OBJ_NULL; // indicate success - } + elem->value = dest[1]; + dest[0] = MP_OBJ_NULL; // indicate success } } } diff --git a/tests/basics/del_attr.py b/tests/basics/del_attr.py index bec7afb848..8487b97e31 100644 --- a/tests/basics/del_attr.py +++ b/tests/basics/del_attr.py @@ -30,3 +30,10 @@ try: del c.x except AttributeError: print("AttributeError") + +# try to del an attribute of a built-in class +try: + del int.to_bytes +except (AttributeError, TypeError): + # uPy raises AttributeError, CPython raises TypeError + print('AttributeError/TypeError') diff --git a/tests/basics/setattr1.py b/tests/basics/setattr1.py index 9693aca819..e4acb14cac 100644 --- a/tests/basics/setattr1.py +++ b/tests/basics/setattr1.py @@ -16,3 +16,10 @@ try: setattr(a, b'var3', 1) except TypeError: print('TypeError') + +# try setattr on a built-in function +try: + setattr(int, 'to_bytes', 1) +except (AttributeError, TypeError): + # uPy raises AttributeError, CPython raises TypeError + print('AttributeError/TypeError') From 1f53ff61fffb4cc9b42ddf7e331e225c1b48b4ff Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 7 Feb 2018 15:55:52 +1100 Subject: [PATCH 280/828] tests/basics: Rename remaining tests that are for built-in functions. For consistency with all of the other tests that are named builtin_XXX.py. --- tests/basics/{enumerate.py => builtin_enumerate.py} | 0 tests/basics/{filter.py => builtin_filter.py} | 0 tests/basics/{getattr1.py => builtin_getattr.py} | 0 tests/basics/{hasattr1.py => builtin_hasattr.py} | 0 tests/basics/{map.py => builtin_map.py} | 0 tests/basics/{print.py => builtin_print.py} | 0 tests/basics/{setattr1.py => builtin_setattr.py} | 0 tests/basics/{zip.py => builtin_zip.py} | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename tests/basics/{enumerate.py => builtin_enumerate.py} (100%) rename tests/basics/{filter.py => builtin_filter.py} (100%) rename tests/basics/{getattr1.py => builtin_getattr.py} (100%) rename tests/basics/{hasattr1.py => builtin_hasattr.py} (100%) rename tests/basics/{map.py => builtin_map.py} (100%) rename tests/basics/{print.py => builtin_print.py} (100%) rename tests/basics/{setattr1.py => builtin_setattr.py} (100%) rename tests/basics/{zip.py => builtin_zip.py} (100%) diff --git a/tests/basics/enumerate.py b/tests/basics/builtin_enumerate.py similarity index 100% rename from tests/basics/enumerate.py rename to tests/basics/builtin_enumerate.py diff --git a/tests/basics/filter.py b/tests/basics/builtin_filter.py similarity index 100% rename from tests/basics/filter.py rename to tests/basics/builtin_filter.py diff --git a/tests/basics/getattr1.py b/tests/basics/builtin_getattr.py similarity index 100% rename from tests/basics/getattr1.py rename to tests/basics/builtin_getattr.py diff --git a/tests/basics/hasattr1.py b/tests/basics/builtin_hasattr.py similarity index 100% rename from tests/basics/hasattr1.py rename to tests/basics/builtin_hasattr.py diff --git a/tests/basics/map.py b/tests/basics/builtin_map.py similarity index 100% rename from tests/basics/map.py rename to tests/basics/builtin_map.py diff --git a/tests/basics/print.py b/tests/basics/builtin_print.py similarity index 100% rename from tests/basics/print.py rename to tests/basics/builtin_print.py diff --git a/tests/basics/setattr1.py b/tests/basics/builtin_setattr.py similarity index 100% rename from tests/basics/setattr1.py rename to tests/basics/builtin_setattr.py diff --git a/tests/basics/zip.py b/tests/basics/builtin_zip.py similarity index 100% rename from tests/basics/zip.py rename to tests/basics/builtin_zip.py From 771dfb0826f7416848b4302ce8ce49a7a556a27f Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 7 Feb 2018 16:10:42 +1100 Subject: [PATCH 281/828] py/modbuiltins: For builtin_chr, use uint8_t instead of char for array. The array should be of type unsigned byte because that is the type of the values being stored. And changing to uint8_t helps to prevent warnings from some static analysers. --- py/modbuiltins.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/py/modbuiltins.c b/py/modbuiltins.c index c8e3235f6f..e6f82df6f4 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -137,7 +137,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_callable_obj, mp_builtin_callable); STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { #if MICROPY_PY_BUILTINS_STR_UNICODE mp_uint_t c = mp_obj_get_int(o_in); - char str[4]; + uint8_t str[4]; int len = 0; if (c < 0x80) { *str = c; len = 1; @@ -159,12 +159,12 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { } else { mp_raise_ValueError("chr() arg not in range(0x110000)"); } - return mp_obj_new_str_via_qstr(str, len); + return mp_obj_new_str_via_qstr((char*)str, len); #else mp_int_t ord = mp_obj_get_int(o_in); if (0 <= ord && ord <= 0xff) { - char str[1] = {ord}; - return mp_obj_new_str_via_qstr(str, 1); + uint8_t str[1] = {ord}; + return mp_obj_new_str_via_qstr((char*)str, 1); } else { mp_raise_ValueError("chr() arg not in range(256)"); } From 923ebe767d2ba8c4534560dc21d3533c37a3f831 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 8 Feb 2018 11:14:30 +1100 Subject: [PATCH 282/828] tests/unix: Add coverage test for calling mp_obj_new_bytearray. --- ports/unix/coverage.c | 10 ++++++++++ tests/unix/extra_coverage.py.exp | 2 ++ 2 files changed, 12 insertions(+) diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 5118f90525..6b6b892856 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -231,6 +231,16 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "%d\n", MP_OBJ_IS_QSTR(mp_obj_str_intern(mp_obj_new_str("intern me", 9)))); } + // bytearray + { + mp_printf(&mp_plat_print, "# bytearray\n"); + + // create a bytearray via mp_obj_new_bytearray + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(mp_obj_new_bytearray(4, "data"), &bufinfo, MP_BUFFER_RW); + mp_printf(&mp_plat_print, "%.*s\n", bufinfo.len, bufinfo.buf); + } + // mpz { mp_printf(&mp_plat_print, "# mpz\n"); diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index bbac5f3d73..26fd2e332d 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -34,6 +34,8 @@ ementation (start=1, stop=2, step=3) # str 1 +# bytearray +data # mpz 1 12345678 From 0b12cc8febe11e43c012b12cb2d6ad59bbda4724 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 8 Feb 2018 11:30:19 +1100 Subject: [PATCH 283/828] .travis.yml,ports/unix/Makefile: Add coverage test for script via stdin. --- .travis.yml | 3 +++ ports/unix/Makefile | 1 + 2 files changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index b98ee99710..27e9fac96f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,6 +58,9 @@ script: - (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --emit native) - (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --via-mpy -d basics float) + # test when input script comes from stdin + - cat tests/basics/0prelim.py | ports/unix/micropython_coverage | grep -q 'abc' + # run coveralls coverage analysis (try to, even if some builds/tests failed) - (cd ports/unix && coveralls --root ../.. --build-root . --gcov $(which gcov) --gcov-options '\-o build-coverage/' --include py --include extmod) diff --git a/ports/unix/Makefile b/ports/unix/Makefile index b5f9f8e7da..f7b260e18d 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -258,6 +258,7 @@ coverage_test: coverage cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests -d thread cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests --emit native cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests --via-mpy -d basics float + cat $(TOP)/tests/basics/0prelim.py | ./micropython_coverage | grep -q 'abc' gcov -o build-coverage/py $(TOP)/py/*.c gcov -o build-coverage/extmod $(TOP)/extmod/*.c From 0c650d427601d5c84bd623d58abc9be5451c576c Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 8 Feb 2018 13:30:33 +1100 Subject: [PATCH 284/828] py/vm: Simplify stack sentinel values for unwind return and jump. This patch simplifies how sentinel values are stored on the stack when doing an unwind return or jump. Instead of storing two values on the stack for an unwind jump it now stores only one: a negative small integer means unwind-return and a non-negative small integer means unwind-jump with the value being the number of exceptions to unwind. The savings in code size are: bare-arm: -56 minimal x86: -68 unix x64: -80 unix nanbox: -4 stm32: -56 cc3200: -64 esp8266: -76 esp32: -156 --- py/vm.c | 61 ++++++++++++++++++++++----------------------------------- 1 file changed, 23 insertions(+), 38 deletions(-) diff --git a/py/vm.c b/py/vm.c index b18a2b5e32..c629a61e2f 100644 --- a/py/vm.c +++ b/py/vm.c @@ -48,14 +48,6 @@ // top element. // Exception stack also grows up, top element is also pointed at. -// Exception stack unwind reasons (WHY_* in CPython-speak) -// TODO perhaps compress this to RETURN=0, JUMP>0, with number of unwinds -// left to do encoded in the JUMP number -typedef enum { - UNWIND_RETURN = 1, - UNWIND_JUMP, -} mp_unwind_reason_t; - #define DECODE_UINT \ mp_uint_t unum = 0; \ do { \ @@ -613,29 +605,18 @@ dispatch_loop: mp_call_method_n_kw(3, 0, sp); SET_TOP(mp_const_none); } else if (MP_OBJ_IS_SMALL_INT(TOP())) { - mp_int_t cause_val = MP_OBJ_SMALL_INT_VALUE(TOP()); - if (cause_val == UNWIND_RETURN) { - // stack: (..., __exit__, ctx_mgr, ret_val, UNWIND_RETURN) - mp_obj_t ret_val = sp[-1]; - sp[-1] = mp_const_none; - sp[0] = mp_const_none; - sp[1] = mp_const_none; - mp_call_method_n_kw(3, 0, sp - 3); - sp[-3] = ret_val; - sp[-2] = MP_OBJ_NEW_SMALL_INT(UNWIND_RETURN); - } else { - assert(cause_val == UNWIND_JUMP); - // stack: (..., __exit__, ctx_mgr, dest_ip, num_exc, UNWIND_JUMP) - mp_obj_t dest_ip = sp[-2]; - mp_obj_t num_exc = sp[-1]; - sp[-2] = mp_const_none; - sp[-1] = mp_const_none; - sp[0] = mp_const_none; - mp_call_method_n_kw(3, 0, sp - 4); - sp[-4] = dest_ip; - sp[-3] = num_exc; - sp[-2] = MP_OBJ_NEW_SMALL_INT(UNWIND_JUMP); - } + // Getting here there are two distinct cases: + // - unwind return, stack: (..., __exit__, ctx_mgr, ret_val, SMALL_INT(-1)) + // - unwind jump, stack: (..., __exit__, ctx_mgr, dest_ip, SMALL_INT(num_exc)) + // For both cases we do exactly the same thing. + mp_obj_t data = sp[-1]; + mp_obj_t cause = sp[0]; + sp[-1] = mp_const_none; + sp[0] = mp_const_none; + sp[1] = mp_const_none; + mp_call_method_n_kw(3, 0, sp - 3); + sp[-3] = data; + sp[-2] = cause; sp -= 2; // we removed (__exit__, ctx_mgr) } else { assert(mp_obj_is_exception_instance(TOP())); @@ -680,10 +661,11 @@ unwind_jump:; // of a "with" block contains the context manager info. // We're going to run "finally" code as a coroutine // (not calling it recursively). Set up a sentinel - // on a stack so it can return back to us when it is + // on the stack so it can return back to us when it is // done (when WITH_CLEANUP or END_FINALLY reached). - PUSH((mp_obj_t)unum); // push number of exception handlers left to unwind - PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_JUMP)); // push sentinel + // The sentinel is the number of exception handlers left to + // unwind, which is a non-negative integer. + PUSH(MP_OBJ_NEW_SMALL_INT(unum)); ip = exc_sp->handler; // get exception handler byte code address exc_sp--; // pop exception handler goto dispatch_loop; // run the exception handler @@ -720,11 +702,14 @@ unwind_jump:; } else if (MP_OBJ_IS_SMALL_INT(TOP())) { // We finished "finally" coroutine and now dispatch back // to our caller, based on TOS value - mp_unwind_reason_t reason = MP_OBJ_SMALL_INT_VALUE(POP()); - if (reason == UNWIND_RETURN) { + mp_int_t cause = MP_OBJ_SMALL_INT_VALUE(POP()); + if (cause < 0) { + // A negative cause indicates unwind return goto unwind_return; } else { - assert(reason == UNWIND_JUMP); + // Otherwise it's an unwind jump and we must push as a raw + // number the number of exception handlers to unwind + PUSH((mp_obj_t)cause); goto unwind_jump; } } else { @@ -1101,7 +1086,7 @@ unwind_return: // (not calling it recursively). Set up a sentinel // on a stack so it can return back to us when it is // done (when WITH_CLEANUP or END_FINALLY reached). - PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_RETURN)); + PUSH(MP_OBJ_NEW_SMALL_INT(-1)); ip = exc_sp->handler; exc_sp--; goto dispatch_loop; From b75cb8392bdf5f8c12072eac3adbdaad53d1e8d2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 8 Feb 2018 14:02:50 +1100 Subject: [PATCH 285/828] py/parsenum: Fix parsing of floats that are close to subnormal. Prior to this patch, a float literal that was close to subnormal would have a loss of precision when parsed. The worst case was something like float('10000000000000000000e-326') which returned 0.0. --- py/parsenum.c | 14 ++++++++++++-- tests/float/float_parse.py | 5 +++++ tests/float/float_parse_doubleprec.py | 5 +++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/py/parsenum.c b/py/parsenum.c index 98e7736851..124489c66e 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -172,10 +172,15 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool #if MICROPY_PY_BUILTINS_FLOAT // DEC_VAL_MAX only needs to be rough and is used to retain precision while not overflowing +// SMALL_NORMAL_VAL is the smallest power of 10 that is still a normal float #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT #define DEC_VAL_MAX 1e20F +#define SMALL_NORMAL_VAL (1e-37F) +#define SMALL_NORMAL_EXP (-37) #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE #define DEC_VAL_MAX 1e200 +#define SMALL_NORMAL_VAL (1e-307) +#define SMALL_NORMAL_EXP (-307) #endif const char *top = str + len; @@ -275,8 +280,13 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool exp_val = -exp_val; } - // apply the exponent - dec_val *= MICROPY_FLOAT_C_FUN(pow)(10, exp_val + exp_extra); + // apply the exponent, making sure it's not a subnormal value + exp_val += exp_extra; + if (exp_val < SMALL_NORMAL_EXP) { + exp_val -= SMALL_NORMAL_EXP; + dec_val *= SMALL_NORMAL_VAL; + } + dec_val *= MICROPY_FLOAT_C_FUN(pow)(10, exp_val); } // negate value if needed diff --git a/tests/float/float_parse.py b/tests/float/float_parse.py index 448eff3bc9..de4ea455fb 100644 --- a/tests/float/float_parse.py +++ b/tests/float/float_parse.py @@ -20,3 +20,8 @@ print(float('.' + '9' * 70 + 'e-50') == float('1e-50')) print(float('.' + '0' * 60 + '1e10') == float('1e-51')) print(float('.' + '0' * 60 + '9e25')) print(float('.' + '0' * 60 + '9e40')) + +# ensure that accuracy is retained when value is close to a subnormal +print(float('1.00000000000000000000e-37')) +print(float('10.0000000000000000000e-38')) +print(float('100.000000000000000000e-39')) diff --git a/tests/float/float_parse_doubleprec.py b/tests/float/float_parse_doubleprec.py index 3566011309..2ea7842f3f 100644 --- a/tests/float/float_parse_doubleprec.py +++ b/tests/float/float_parse_doubleprec.py @@ -14,3 +14,8 @@ print(float('.' + '9' * 400 + 'e-100')) print(float('.' + '0' * 400 + '9e100')) print(float('.' + '0' * 400 + '9e200')) print(float('.' + '0' * 400 + '9e400')) + +# ensure that accuracy is retained when value is close to a subnormal +print(float('1.00000000000000000000e-307')) +print(float('10.0000000000000000000e-308')) +print(float('100.000000000000000000e-309')) From bbb08431f3c45d94c1e6aa0762b8f13ccce1fe8e Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 8 Feb 2018 14:35:43 +1100 Subject: [PATCH 286/828] py/objfloat: Fix case of raising 0 to -infinity. It was raising an exception but it should return infinity. --- py/objfloat.c | 2 +- tests/float/builtin_float_pow.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 tests/float/builtin_float_pow.py diff --git a/py/objfloat.c b/py/objfloat.c index 75212a4d22..e4d5a65701 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -293,7 +293,7 @@ mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t break; case MP_BINARY_OP_POWER: case MP_BINARY_OP_INPLACE_POWER: - if (lhs_val == 0 && rhs_val < 0) { + if (lhs_val == 0 && rhs_val < 0 && !isinf(rhs_val)) { goto zero_division_error; } if (lhs_val < 0 && rhs_val != MICROPY_FLOAT_C_FUN(floor)(rhs_val)) { diff --git a/tests/float/builtin_float_pow.py b/tests/float/builtin_float_pow.py new file mode 100644 index 0000000000..2de1b48176 --- /dev/null +++ b/tests/float/builtin_float_pow.py @@ -0,0 +1,11 @@ +# test builtin pow function with float args + +print(pow(0.0, 0.0)) +print(pow(0, 1.0)) +print(pow(1.0, 1)) +print(pow(2.0, 3.0)) +print(pow(2.0, -4.0)) + +print(pow(0.0, float('inf'))) +print(pow(0.0, float('-inf'))) +print(pow(0.0, float('nan'))) From 2d5bab46be2175ff0d8db02a74afc34f0c8d287f Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 9 Feb 2018 18:40:13 +1100 Subject: [PATCH 287/828] stm32: Add mpconfigboard_common.h with common/default board settings. This file mirrors py/mpconfig.h but for board-level config options. It provides a default configuration, to be overridden by a specific mpconfigboard.h file, as well as setting up certain macros to automatically configure a board. --- ports/stm32/mpconfigboard_common.h | 116 +++++++++++++++++++++++++++++ ports/stm32/mpconfigport.h | 36 +-------- 2 files changed, 120 insertions(+), 32 deletions(-) create mode 100644 ports/stm32/mpconfigboard_common.h diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h new file mode 100644 index 0000000000..1e3d6913b4 --- /dev/null +++ b/ports/stm32/mpconfigboard_common.h @@ -0,0 +1,116 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// Common settings and defaults for board configuration. +// The defaults here should be overridden in mpconfigboard.h. + +/*****************************************************************************/ +// Feature settings with defaults + +// Whether to enable the RTC, exposed as pyb.RTC +#ifndef MICROPY_HW_ENABLE_RTC +#define MICROPY_HW_ENABLE_RTC (0) +#endif + +// Whether to enable the hardware RNG peripheral, exposed as pyb.rng() +#ifndef MICROPY_HW_ENABLE_RNG +#define MICROPY_HW_ENABLE_RNG (0) +#endif + +// Whether to enable the DAC peripheral, exposed as pyb.DAC +#ifndef MICROPY_HW_ENABLE_DAC +#define MICROPY_HW_ENABLE_DAC (0) +#endif + +// Whether to enable the CAN peripheral, exposed as pyb.CAN +#ifndef MICROPY_HW_ENABLE_CAN +#define MICROPY_HW_ENABLE_CAN (0) +#endif + +// Whether to enable the PA0-PA3 servo driver, exposed as pyb.Servo +#ifndef MICROPY_HW_ENABLE_SERVO +#define MICROPY_HW_ENABLE_SERVO (0) +#endif + +// Whether to enable a USR switch, exposed as pyb.Switch +#ifndef MICROPY_HW_HAS_SWITCH +#define MICROPY_HW_HAS_SWITCH (0) +#endif + +// Whether to expose internal flash storage as pyb.Flash +#ifndef MICROPY_HW_HAS_FLASH +#define MICROPY_HW_HAS_FLASH (0) +#endif + +// Whether to enable the SD card interface, exposed as pyb.SDCard +#ifndef MICROPY_HW_HAS_SDCARD +#define MICROPY_HW_HAS_SDCARD (0) +#endif + +// Whether to enable the MMA7660 driver, exposed as pyb.Accel +#ifndef MICROPY_HW_HAS_MMA7660 +#define MICROPY_HW_HAS_MMA7660 (0) +#endif + +// Whether to enable the LCD32MK driver, exposed as pyb.LCD +#ifndef MICROPY_HW_HAS_LCD +#define MICROPY_HW_HAS_LCD (0) +#endif + +/*****************************************************************************/ +// General configuration + +// Define the maximum number of peripherals that the MCU supports +#if defined(MCU_SERIES_F7) +#define PYB_EXTI_NUM_VECTORS (24) +#define MICROPY_HW_MAX_TIMER (17) +#define MICROPY_HW_MAX_UART (8) +#elif defined(MCU_SERIES_L4) +#define PYB_EXTI_NUM_VECTORS (23) +#define MICROPY_HW_MAX_TIMER (17) +#define MICROPY_HW_MAX_UART (6) +#else +#define PYB_EXTI_NUM_VECTORS (23) +#define MICROPY_HW_MAX_TIMER (14) +#define MICROPY_HW_MAX_UART (6) +#endif + +// Enable hardware I2C if there are any peripherals defined +#if defined(MICROPY_HW_I2C1_SCL) || defined(MICROPY_HW_I2C2_SCL) \ + || defined(MICROPY_HW_I2C3_SCL) || defined(MICROPY_HW_I2C4_SCL) +#define MICROPY_HW_ENABLE_HW_I2C (1) +#else +#define MICROPY_HW_ENABLE_HW_I2C (0) +#endif + +// USB configuration +// see stm32f4XX_hal_conf.h USE_USB_FS & USE_USB_HS +// at the moment only USB_FS is supported +#define USE_DEVICE_MODE +//#define USE_HOST_MODE + +// Pin definition header file +#define MICROPY_PIN_DEFS_PORT_H "pin_defs_stm32.h" diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 6fa286b262..0ade01d158 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -29,6 +29,7 @@ // board specific definitions #include "mpconfigboard.h" +#include "mpconfigboard_common.h" // memory allocation policies #define MICROPY_ALLOC_PATH_MAX (128) @@ -131,6 +132,9 @@ #define MICROPY_PY_MACHINE_PULSE (1) #define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new #define MICROPY_PY_MACHINE_I2C (1) +#if MICROPY_HW_ENABLE_HW_I2C +#define MICROPY_PY_MACHINE_I2C_MAKE_NEW machine_hard_i2c_make_new +#endif #define MICROPY_PY_MACHINE_SPI (1) #define MICROPY_PY_MACHINE_SPI_MSB (SPI_FIRSTBIT_MSB) #define MICROPY_PY_MACHINE_SPI_LSB (SPI_FIRSTBIT_LSB) @@ -230,31 +234,6 @@ extern const struct _mp_obj_module_t mp_module_onewire; { MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, \ { MP_ROM_QSTR(MP_QSTR_stm), MP_ROM_PTR(&stm_module) }, \ -#if defined(MCU_SERIES_F7) -#define PYB_EXTI_NUM_VECTORS (24) -#define MICROPY_HW_MAX_TIMER (17) -#define MICROPY_HW_MAX_UART (8) -#elif defined(MCU_SERIES_L4) -#define PYB_EXTI_NUM_VECTORS (23) -#define MICROPY_HW_MAX_TIMER (17) -#define MICROPY_HW_MAX_UART (6) -#else -#define PYB_EXTI_NUM_VECTORS (23) -#define MICROPY_HW_MAX_TIMER (14) -#define MICROPY_HW_MAX_UART (6) -#endif - -// enable hardware I2C if there are any peripherals defined -#define MICROPY_HW_ENABLE_HW_I2C ( \ - defined(MICROPY_HW_I2C1_SCL) \ - || defined(MICROPY_HW_I2C2_SCL) \ - || defined(MICROPY_HW_I2C3_SCL) \ - || defined(MICROPY_HW_I2C4_SCL) \ -) -#if MICROPY_HW_ENABLE_HW_I2C -#define MICROPY_PY_MACHINE_I2C_MAKE_NEW machine_hard_i2c_make_new -#endif - #define MP_STATE_PORT MP_STATE_VM #define MICROPY_PORT_ROOT_POINTERS \ @@ -361,12 +340,5 @@ static inline mp_uint_t disable_irq(void) { #define free(p) m_free(p) #define realloc(p, n) m_realloc(p, n) -// see stm32f4XX_hal_conf.h USE_USB_FS & USE_USB_HS -// at the moment only USB_FS is supported -#define USE_DEVICE_MODE -//#define USE_HOST_MODE - // We need to provide a declaration/definition of alloca() #include - -#define MICROPY_PIN_DEFS_PORT_H "pin_defs_stm32.h" From 02f88cb2df73b7cf2baf7568c26999269baa45f0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 9 Feb 2018 18:40:40 +1100 Subject: [PATCH 288/828] stm32/boards: Remove all config options that are set to defaults. mpconfigboard_common.h now sets the defaults so there is no longer a need to explicitly list all configuration options in a board's mpconfigboard.h file. --- ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h | 9 --------- ports/stm32/boards/CERB40/mpconfigboard.h | 7 ------- ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h | 8 -------- ports/stm32/boards/HYDRABUS/mpconfigboard.h | 7 ------- ports/stm32/boards/LIMIFROG/mpconfigboard.h | 8 -------- ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h | 7 ------- ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h | 7 ------- ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h | 6 ------ ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h | 6 ------ ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h | 2 -- ports/stm32/boards/OLIMEX_E407/mpconfigboard.h | 5 ----- ports/stm32/boards/PYBLITEV10/mpconfigboard.h | 5 ----- ports/stm32/boards/PYBV10/mpconfigboard.h | 2 -- ports/stm32/boards/PYBV11/mpconfigboard.h | 2 -- ports/stm32/boards/PYBV3/mpconfigboard.h | 3 --- ports/stm32/boards/PYBV4/mpconfigboard.h | 2 -- ports/stm32/boards/STM32F411DISC/mpconfigboard.h | 8 -------- ports/stm32/boards/STM32F429DISC/mpconfigboard.h | 7 ------- ports/stm32/boards/STM32F439/mpconfigboard.h | 6 ------ ports/stm32/boards/STM32F4DISC/mpconfigboard.h | 6 ------ ports/stm32/boards/STM32F769DISC/mpconfigboard.h | 6 ------ ports/stm32/boards/STM32F7DISC/mpconfigboard.h | 6 ------ ports/stm32/boards/STM32L476DISC/mpconfigboard.h | 8 -------- 23 files changed, 133 deletions(-) diff --git a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h index 77f029c006..cc4f36526a 100644 --- a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h +++ b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h @@ -2,17 +2,8 @@ #define MICROPY_HW_MCU_NAME "STM32L475" #define MICROPY_HW_HAS_SWITCH (1) -#define MICROPY_HW_HAS_FLASH (0) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) -#define MICROPY_HW_ENABLE_DAC (0) -#define MICROPY_HW_ENABLE_CAN (0) // MSI is used and is 4MHz #define MICROPY_HW_CLK_PLLM (1) diff --git a/ports/stm32/boards/CERB40/mpconfigboard.h b/ports/stm32/boards/CERB40/mpconfigboard.h index e668ba4e14..444185ca01 100644 --- a/ports/stm32/boards/CERB40/mpconfigboard.h +++ b/ports/stm32/boards/CERB40/mpconfigboard.h @@ -1,16 +1,9 @@ #define MICROPY_HW_BOARD_NAME "Cerb40" #define MICROPY_HW_MCU_NAME "STM32F405RG" -#define MICROPY_HW_HAS_SWITCH (0) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_CAN (1) diff --git a/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h index d065180d8a..d3ae825b80 100644 --- a/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h +++ b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h @@ -9,16 +9,8 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) -#define MICROPY_HW_ENABLE_RNG (0) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) -#define MICROPY_HW_ENABLE_DAC (0) -#define MICROPY_HW_ENABLE_CAN (0) // Pico has an 8 MHz HSE and the F401 does 84 MHz max #define MICROPY_HW_CLK_PLLM (5) diff --git a/ports/stm32/boards/HYDRABUS/mpconfigboard.h b/ports/stm32/boards/HYDRABUS/mpconfigboard.h index 8eaa367474..4d5b12866b 100644 --- a/ports/stm32/boards/HYDRABUS/mpconfigboard.h +++ b/ports/stm32/boards/HYDRABUS/mpconfigboard.h @@ -4,15 +4,8 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) -#define MICROPY_HW_ENABLE_RTC (0) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (0) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) diff --git a/ports/stm32/boards/LIMIFROG/mpconfigboard.h b/ports/stm32/boards/LIMIFROG/mpconfigboard.h index 42b862fcf5..dfa159fc7c 100644 --- a/ports/stm32/boards/LIMIFROG/mpconfigboard.h +++ b/ports/stm32/boards/LIMIFROG/mpconfigboard.h @@ -3,16 +3,8 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) -#define MICROPY_HW_ENABLE_DAC (0) -#define MICROPY_HW_ENABLE_CAN (0) #define MICROPY_BOARD_EARLY_INIT LIMIFROG_board_early_init void LIMIFROG_board_early_init(void); diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h index 9586ae4e55..fc83d769e1 100644 --- a/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h +++ b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h @@ -8,15 +8,8 @@ // SPI, so the driver needs to be converted to support that before // we can turn this on. #define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) -#define MICROPY_HW_ENABLE_RTC (0) -#define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) -#define MICROPY_HW_ENABLE_DAC (0) -#define MICROPY_HW_ENABLE_CAN (0) void NETDUINO_PLUS_2_board_early_init(void); #define MICROPY_BOARD_EARLY_INIT NETDUINO_PLUS_2_board_early_init diff --git a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h index 608beef672..4df87f0602 100644 --- a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h @@ -3,15 +3,8 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) -#define MICROPY_HW_ENABLE_DAC (0) #define MICROPY_HW_ENABLE_CAN (1) // HSE is 8MHz diff --git a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h index c5b84938cd..0fe6030bb3 100644 --- a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h @@ -8,14 +8,8 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_CAN (1) diff --git a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h index 8952bce82f..c3fd016c19 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h @@ -8,14 +8,8 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_CAN (1) diff --git a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h index f2474619fe..806f8207d0 100644 --- a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h @@ -3,8 +3,6 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RTC (1) // MSI is used and is 4MHz diff --git a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h index 86dfd1166c..c1e67e3d86 100644 --- a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h +++ b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h @@ -4,13 +4,8 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_CAN (1) diff --git a/ports/stm32/boards/PYBLITEV10/mpconfigboard.h b/ports/stm32/boards/PYBLITEV10/mpconfigboard.h index 090ba4cf1b..5037073f97 100644 --- a/ports/stm32/boards/PYBLITEV10/mpconfigboard.h +++ b/ports/stm32/boards/PYBLITEV10/mpconfigboard.h @@ -5,14 +5,9 @@ #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_HAS_MMA7660 (1) -#define MICROPY_HW_HAS_LIS3DSH (0) #define MICROPY_HW_HAS_LCD (1) -#define MICROPY_HW_ENABLE_RNG (0) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) -#define MICROPY_HW_ENABLE_DAC (0) -#define MICROPY_HW_ENABLE_CAN (0) // HSE is 12MHz #define MICROPY_HW_CLK_PLLM (12) diff --git a/ports/stm32/boards/PYBV10/mpconfigboard.h b/ports/stm32/boards/PYBV10/mpconfigboard.h index c06022a34d..bb1d620f61 100644 --- a/ports/stm32/boards/PYBV10/mpconfigboard.h +++ b/ports/stm32/boards/PYBV10/mpconfigboard.h @@ -5,11 +5,9 @@ #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_HAS_MMA7660 (1) -#define MICROPY_HW_HAS_LIS3DSH (0) #define MICROPY_HW_HAS_LCD (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_CAN (1) diff --git a/ports/stm32/boards/PYBV11/mpconfigboard.h b/ports/stm32/boards/PYBV11/mpconfigboard.h index c69e52cc50..32377513ac 100644 --- a/ports/stm32/boards/PYBV11/mpconfigboard.h +++ b/ports/stm32/boards/PYBV11/mpconfigboard.h @@ -5,11 +5,9 @@ #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_HAS_MMA7660 (1) -#define MICROPY_HW_HAS_LIS3DSH (0) #define MICROPY_HW_HAS_LCD (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_CAN (1) diff --git a/ports/stm32/boards/PYBV3/mpconfigboard.h b/ports/stm32/boards/PYBV3/mpconfigboard.h index 1f49af4da1..fccba7e722 100644 --- a/ports/stm32/boards/PYBV3/mpconfigboard.h +++ b/ports/stm32/boards/PYBV3/mpconfigboard.h @@ -5,11 +5,8 @@ #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_HAS_MMA7660 (1) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_CAN (1) diff --git a/ports/stm32/boards/PYBV4/mpconfigboard.h b/ports/stm32/boards/PYBV4/mpconfigboard.h index 2a4829c3e3..b1678512b5 100644 --- a/ports/stm32/boards/PYBV4/mpconfigboard.h +++ b/ports/stm32/boards/PYBV4/mpconfigboard.h @@ -5,11 +5,9 @@ #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_HAS_MMA7660 (1) -#define MICROPY_HW_HAS_LIS3DSH (0) #define MICROPY_HW_HAS_LCD (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_CAN (1) diff --git a/ports/stm32/boards/STM32F411DISC/mpconfigboard.h b/ports/stm32/boards/STM32F411DISC/mpconfigboard.h index 1488cd7640..3b3b0db53c 100644 --- a/ports/stm32/boards/STM32F411DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F411DISC/mpconfigboard.h @@ -3,16 +3,8 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) -#define MICROPY_HW_ENABLE_RNG (0) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) -#define MICROPY_HW_ENABLE_DAC (0) -#define MICROPY_HW_ENABLE_CAN (0) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (5) diff --git a/ports/stm32/boards/STM32F429DISC/mpconfigboard.h b/ports/stm32/boards/STM32F429DISC/mpconfigboard.h index fc07020252..a4c46325a5 100644 --- a/ports/stm32/boards/STM32F429DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F429DISC/mpconfigboard.h @@ -3,15 +3,8 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) -#define MICROPY_HW_ENABLE_DAC (0) #define MICROPY_HW_ENABLE_CAN (1) // HSE is 8MHz diff --git a/ports/stm32/boards/STM32F439/mpconfigboard.h b/ports/stm32/boards/STM32F439/mpconfigboard.h index eca79bf582..7ead50a215 100644 --- a/ports/stm32/boards/STM32F439/mpconfigboard.h +++ b/ports/stm32/boards/STM32F439/mpconfigboard.h @@ -1,16 +1,10 @@ #define MICROPY_HW_BOARD_NAME "CustomPCB" #define MICROPY_HW_MCU_NAME "STM32F439" -#define MICROPY_HW_HAS_SWITCH (0) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) //works with no SD card too -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_CAN (1) diff --git a/ports/stm32/boards/STM32F4DISC/mpconfigboard.h b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h index 688a1ef621..df4222c287 100644 --- a/ports/stm32/boards/STM32F4DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h @@ -3,14 +3,8 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (1) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_CAN (1) diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h index 50b9c1618f..4da9dcd90e 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h @@ -8,14 +8,8 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) -#define MICROPY_HW_ENABLE_DAC (0) #define MICROPY_HW_ENABLE_CAN (1) // HSE is 25MHz diff --git a/ports/stm32/boards/STM32F7DISC/mpconfigboard.h b/ports/stm32/boards/STM32F7DISC/mpconfigboard.h index 41d49f64b5..1ee8e62777 100644 --- a/ports/stm32/boards/STM32F7DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F7DISC/mpconfigboard.h @@ -4,14 +4,8 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) -#define MICROPY_HW_ENABLE_DAC (0) #define MICROPY_HW_ENABLE_CAN (1) #define MICROPY_BOARD_EARLY_INIT STM32F7DISC_board_early_init diff --git a/ports/stm32/boards/STM32L476DISC/mpconfigboard.h b/ports/stm32/boards/STM32L476DISC/mpconfigboard.h index 9dbadd5300..87ab3d6a6c 100644 --- a/ports/stm32/boards/STM32L476DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32L476DISC/mpconfigboard.h @@ -6,16 +6,8 @@ void STM32L476DISC_board_early_init(void); #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) -#define MICROPY_HW_ENABLE_DAC (0) -#define MICROPY_HW_ENABLE_CAN (0) // use external SPI flash for storage #define MICROPY_HW_SPIFLASH_SIZE_BITS (128 * 1024 * 1024) From 8e1cb58a23372594f5a2b5baba91f8e570b7da21 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 12 Feb 2018 17:22:59 +1100 Subject: [PATCH 289/828] stm32/usbdev: Fix USBD setup request handler to use correct recipient. Prior to this patch the USBD driver did not handle the recipient correctly for setup requests. It was not interpreting the req->wIndex field in the right way: in some cases this field indicates the endpoint number but the code was assuming it always indicated the interface number. This patch fixes this. The only noticeable change is to the MSC interface, which should now correctly respond to the USB_REQ_CLEAR_FEATURE request and hence unmount properly from the host when requested. --- .../stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 48 +++++++++++++++---- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c index 394fceb75c..a1a7cff6c1 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -821,13 +821,45 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; + // Work out the recipient of the setup request + uint8_t mode = usbd->usbd_mode; + uint8_t recipient = 0; + switch (req->bmRequest & USB_REQ_RECIPIENT_MASK) { + case USB_REQ_RECIPIENT_INTERFACE: { + uint16_t iface = req->wIndex; + if ((mode & USBD_MODE_CDC) && iface == usbd->cdc_iface_num) { + recipient = USBD_MODE_CDC; + } else if ((mode & USBD_MODE_MSC) && iface == MSC_IFACE_NUM_WITH_CDC) { + recipient = USBD_MODE_MSC; + } else if ((mode & USBD_MODE_HID) && iface == usbd->hid_iface_num) { + recipient = USBD_MODE_HID; + } + break; + } + case USB_REQ_RECIPIENT_ENDPOINT: { + uint8_t ep = req->wIndex & 0x7f; + if ((mode & USBD_MODE_CDC) && (ep == CDC_OUT_EP || ep == (CDC_CMD_EP & 0x7f))) { + recipient = USBD_MODE_CDC; + } else if ((mode & USBD_MODE_MSC) && ep == MSC_OUT_EP) { + recipient = USBD_MODE_MSC; + } else if ((mode & USBD_MODE_HID) && ep == usbd->hid_out_ep) { + recipient = USBD_MODE_HID; + } + break; + } + } + + // Fail the request if we didn't have a valid recipient + if (recipient == 0) { + USBD_CtlError(pdev, req); + return USBD_FAIL; + } + switch (req->bmRequest & USB_REQ_TYPE_MASK) { // Class request case USB_REQ_TYPE_CLASS: - // req->wIndex is the recipient interface number - if ((usbd->usbd_mode & USBD_MODE_CDC) && req->wIndex == usbd->cdc_iface_num) { - // CDC component + if (recipient == USBD_MODE_CDC) { if (req->wLength) { if (req->bmRequest & 0x80) { // device-to-host request @@ -844,8 +876,7 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp // Transfer the command to the interface layer return usbd_cdc_control(usbd->cdc, req->bRequest, NULL, req->wValue); } - } else if ((usbd->usbd_mode & USBD_MODE_MSC) && req->wIndex == MSC_IFACE_NUM_WITH_CDC) { - // MSC component + } else if (recipient == USBD_MODE_MSC) { switch (req->bRequest) { case BOT_GET_MAX_LUN: if ((req->wValue == 0) && (req->wLength == 1) && ((req->bmRequest & 0x80) == 0x80)) { @@ -870,7 +901,7 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp USBD_CtlError(pdev, req); return USBD_FAIL; } - } else if ((usbd->usbd_mode & USBD_MODE_HID) && req->wIndex == usbd->hid_iface_num) { + } else if (recipient == USBD_MODE_HID) { switch (req->bRequest) { case HID_REQ_SET_PROTOCOL: usbd->HID_ClassData.Protocol = (uint8_t)(req->wValue); @@ -895,9 +926,8 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp } break; - // Interface & Endpoint request case USB_REQ_TYPE_STANDARD: - if ((usbd->usbd_mode & USBD_MODE_MSC) && req->wIndex == MSC_IFACE_NUM_WITH_CDC) { + if (recipient == USBD_MODE_MSC) { switch (req->bRequest) { case USB_REQ_GET_INTERFACE : USBD_CtlSendData(pdev, (uint8_t *)&usbd->MSC_BOT_ClassData.interface, 1); @@ -924,7 +954,7 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp MSC_BOT_CplClrFeature(pdev, (uint8_t)req->wIndex); break; } - } else if ((usbd->usbd_mode & USBD_MODE_HID) && req->wIndex == usbd->hid_iface_num) { + } else if (recipient == USBD_MODE_HID) { switch (req->bRequest) { case USB_REQ_GET_DESCRIPTOR: { uint16_t len = 0; From 3eb0694b97c6a8f0e93b874549aac40d8b78b0e5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 13 Feb 2018 15:37:35 +1100 Subject: [PATCH 290/828] stm32: Update HAL macro and constant names to use newer versions. Newer versions of the HAL use names which are cleaner and more self-consistent amongst the HAL itself. This patch switches to use those names in most places so it is easier to update the HAL in the future. --- ports/stm32/adc.c | 6 +- ports/stm32/boards/LIMIFROG/board_init.c | 6 +- .../stm32/boards/NETDUINO_PLUS_2/board_init.c | 4 +- ports/stm32/boards/STM32F7DISC/board_init.c | 4 +- ports/stm32/can.c | 2 +- ports/stm32/dma.c | 8 +-- ports/stm32/extint.c | 2 +- ports/stm32/fatfs_port.c | 4 +- ports/stm32/main.c | 8 +-- ports/stm32/modmachine.c | 2 +- ports/stm32/modutime.c | 8 +-- ports/stm32/mphalport.c | 44 ++++++------- ports/stm32/pin.c | 2 +- ports/stm32/rtc.c | 16 ++--- ports/stm32/spi.c | 10 +-- ports/stm32/timer.c | 64 +++++++++---------- ports/stm32/uart.c | 64 +++++++++---------- ports/stm32/usbd_conf.c | 26 ++++---- 18 files changed, 140 insertions(+), 140 deletions(-) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 0e1cf4b646..b8b4f4e56a 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -51,7 +51,7 @@ /* ADC defintions */ #define ADCx (ADC1) -#define ADCx_CLK_ENABLE __ADC1_CLK_ENABLE +#define ADCx_CLK_ENABLE __HAL_RCC_ADC1_CLK_ENABLE #define ADC_NUM_CHANNELS (19) #if defined(MCU_SERIES_F4) @@ -261,7 +261,7 @@ STATIC uint32_t adc_read_channel(ADC_HandleTypeDef *adcHandle) { HAL_ADC_Start(adcHandle); if (HAL_ADC_PollForConversion(adcHandle, 10) == HAL_OK - && (HAL_ADC_GetState(adcHandle) & HAL_ADC_STATE_EOC_REG) == HAL_ADC_STATE_EOC_REG) { + && (HAL_ADC_GetState(adcHandle) & HAL_ADC_STATE_REG_EOC) == HAL_ADC_STATE_REG_EOC) { rawValue = HAL_ADC_GetValue(adcHandle); } HAL_ADC_Stop(adcHandle); @@ -535,7 +535,7 @@ uint32_t adc_config_and_read_channel(ADC_HandleTypeDef *adcHandle, uint32_t chan } int adc_get_resolution(ADC_HandleTypeDef *adcHandle) { - uint32_t res_reg = __HAL_ADC_GET_RESOLUTION(adcHandle); + uint32_t res_reg = ADC_GET_RESOLUTION(adcHandle); switch (res_reg) { case ADC_RESOLUTION_6B: return 6; diff --git a/ports/stm32/boards/LIMIFROG/board_init.c b/ports/stm32/boards/LIMIFROG/board_init.c index 72f9208424..67ccf23cc5 100644 --- a/ports/stm32/boards/LIMIFROG/board_init.c +++ b/ports/stm32/boards/LIMIFROG/board_init.c @@ -104,10 +104,10 @@ static void LBF_DFU_If_Needed(void) // Initialize and assert pin BTLE_RST // (hw reset to BLE module, so it won't drive UART3) - __GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_LOW; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Pin = BT_RST_PIN; HAL_GPIO_Init(BT_RST_PORT, &GPIO_InitStruct); @@ -124,7 +124,7 @@ static void LBF_DFU_If_Needed(void) // Initialize Extension Port Position 10 = PB8 (bears I2C1_SCL) // Use weak pull-up to detect if pin is externally pulled low - __GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Pin = CONN_POS10_PIN; diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c b/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c index 085034b2d8..53df72503b 100644 --- a/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c +++ b/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c @@ -2,11 +2,11 @@ void NETDUINO_PLUS_2_board_early_init(void) { - __GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); // Turn off the backlight. LCD_BL_CTRL = PK3 GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Pull = GPIO_PULLUP; diff --git a/ports/stm32/boards/STM32F7DISC/board_init.c b/ports/stm32/boards/STM32F7DISC/board_init.c index 4530a47063..dd268fb9c0 100644 --- a/ports/stm32/boards/STM32F7DISC/board_init.c +++ b/ports/stm32/boards/STM32F7DISC/board_init.c @@ -3,13 +3,13 @@ void STM32F7DISC_board_early_init(void) { GPIO_InitTypeDef GPIO_InitStructure; - __GPIOK_CLK_ENABLE(); + __HAL_RCC_GPIOK_CLK_ENABLE(); // Turn off the backlight. LCD_BL_CTRL = PK3 GPIO_InitStructure.Pin = GPIO_PIN_3; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Pull = GPIO_PULLUP; - GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOK, &GPIO_InitStructure); HAL_GPIO_WritePin(GPIOK, GPIO_PIN_3, GPIO_PIN_RESET); } diff --git a/ports/stm32/can.c b/ports/stm32/can.c index d71a8bec7e..3d94b191c6 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -125,7 +125,7 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { // init GPIO GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Pin = GPIO_Pin; - GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; GPIO_InitStructure.Pull = GPIO_PULLUP; GPIO_InitStructure.Alternate = GPIO_AF_CANx; diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index df6275d652..f43daaab06 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -373,7 +373,7 @@ static void dma_enable_clock(dma_id_t dma_id) { if (dma_id < NSTREAMS_PER_CONTROLLER) { if (((old_enable_mask & DMA1_ENABLE_MASK) == 0) && !DMA1_IS_CLK_ENABLED()) { - __DMA1_CLK_ENABLE(); + __HAL_RCC_DMA1_CLK_ENABLE(); // We just turned on the clock. This means that anything stored // in dma_last_channel (for DMA1) needs to be invalidated. @@ -384,7 +384,7 @@ static void dma_enable_clock(dma_id_t dma_id) { } } else { if (((old_enable_mask & DMA2_ENABLE_MASK) == 0) && !DMA2_IS_CLK_ENABLED()) { - __DMA2_CLK_ENABLE(); + __HAL_RCC_DMA2_CLK_ENABLE(); // We just turned on the clock. This means that anything stored // in dma_last_channel (for DMA1) needs to be invalidated. @@ -494,9 +494,9 @@ void dma_idle_handler(int tick) { // Now we'll really disable the clock. dma_idle.counter[controller] = 0; if (controller == 0) { - __DMA1_CLK_DISABLE(); + __HAL_RCC_DMA1_CLK_DISABLE(); } else { - __DMA2_CLK_DISABLE(); + __HAL_RCC_DMA2_CLK_DISABLE(); } } else { // Something is still active, but the counter never got diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c index 41943f1cdb..423af2ac36 100644 --- a/ports/stm32/extint.c +++ b/ports/stm32/extint.c @@ -203,7 +203,7 @@ uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t ca exti.Pin = pin->pin_mask; exti.Mode = mode; exti.Pull = pull; - exti.Speed = GPIO_SPEED_FAST; + exti.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(pin->gpio, &exti); // Calling HAL_GPIO_Init does an implicit extint_enable diff --git a/ports/stm32/fatfs_port.c b/ports/stm32/fatfs_port.c index 17ec3f7266..d0e311ed77 100644 --- a/ports/stm32/fatfs_port.c +++ b/ports/stm32/fatfs_port.c @@ -32,7 +32,7 @@ DWORD get_fattime(void) { rtc_init_finalise(); RTC_TimeTypeDef time; RTC_DateTypeDef date; - HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN); - HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN); + HAL_RTC_GetTime(&RTCHandle, &time, RTC_FORMAT_BIN); + HAL_RTC_GetDate(&RTCHandle, &date, RTC_FORMAT_BIN); return ((2000 + date.Year - 1980) << 25) | ((date.Month) << 21) | ((date.Date) << 16) | ((time.Hours) << 11) | ((time.Minutes) << 5) | (time.Seconds / 2); } diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 9d568675e3..92a6100c98 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -428,10 +428,10 @@ int main(void) { SystemClock_Config(); // enable GPIO clocks - __GPIOA_CLK_ENABLE(); - __GPIOB_CLK_ENABLE(); - __GPIOC_CLK_ENABLE(); - __GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) #if defined(__HAL_RCC_DTCMRAMEN_CLK_ENABLE) diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index 3645fe60e7..363fbe3219 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -223,7 +223,7 @@ STATIC NORETURN mp_obj_t machine_bootloader(void) { ((void (*)(void)) *((uint32_t*) 0x1FF00004))(); #else - __HAL_REMAPMEMORY_SYSTEMFLASH(); + __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); // arm-none-eabi-gcc 4.9.0 does not correctly inline this // MSP function, so we write it out explicitly here. diff --git a/ports/stm32/modutime.c b/ports/stm32/modutime.c index 54045f4c5c..6b5c841151 100644 --- a/ports/stm32/modutime.c +++ b/ports/stm32/modutime.c @@ -60,8 +60,8 @@ STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) { rtc_init_finalise(); RTC_DateTypeDef date; RTC_TimeTypeDef time; - HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN); - HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN); + HAL_RTC_GetTime(&RTCHandle, &time, RTC_FORMAT_BIN); + HAL_RTC_GetDate(&RTCHandle, &date, RTC_FORMAT_BIN); mp_obj_t tuple[8] = { mp_obj_new_int(2000 + date.Year), mp_obj_new_int(date.Month), @@ -123,8 +123,8 @@ STATIC mp_obj_t time_time(void) { rtc_init_finalise(); RTC_DateTypeDef date; RTC_TimeTypeDef time; - HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN); - HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN); + HAL_RTC_GetTime(&RTCHandle, &time, RTC_FORMAT_BIN); + HAL_RTC_GetDate(&RTCHandle, &date, RTC_FORMAT_BIN); return mp_obj_new_int(timeutils_seconds_since_2000(2000 + date.Year, date.Month, date.Date, time.Hours, time.Minutes, time.Seconds)); } MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c index e9c4f28f79..2252e4f577 100644 --- a/ports/stm32/mphalport.c +++ b/ports/stm32/mphalport.c @@ -99,53 +99,53 @@ void mp_hal_ticks_cpu_enable(void) { void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) { if (0) { - #ifdef __GPIOA_CLK_ENABLE + #ifdef __HAL_RCC_GPIOA_CLK_ENABLE } else if (gpio == GPIOA) { - __GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); #endif - #ifdef __GPIOB_CLK_ENABLE + #ifdef __HAL_RCC_GPIOB_CLK_ENABLE } else if (gpio == GPIOB) { - __GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); #endif - #ifdef __GPIOC_CLK_ENABLE + #ifdef __HAL_RCC_GPIOC_CLK_ENABLE } else if (gpio == GPIOC) { - __GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); #endif - #ifdef __GPIOD_CLK_ENABLE + #ifdef __HAL_RCC_GPIOD_CLK_ENABLE } else if (gpio == GPIOD) { - __GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); #endif - #ifdef __GPIOE_CLK_ENABLE + #ifdef __HAL_RCC_GPIOE_CLK_ENABLE } else if (gpio == GPIOE) { - __GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); #endif - #if defined(GPIOF) && defined(__GPIOF_CLK_ENABLE) + #ifdef __HAL_RCC_GPIOF_CLK_ENABLE } else if (gpio == GPIOF) { - __GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); #endif - #if defined(GPIOG) && defined(__GPIOG_CLK_ENABLE) + #ifdef __HAL_RCC_GPIOG_CLK_ENABLE } else if (gpio == GPIOG) { #if defined(STM32L476xx) || defined(STM32L486xx) // Port G pins 2 thru 15 are powered using VddIO2 on these MCUs. HAL_PWREx_EnableVddIO2(); #endif - __GPIOG_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); #endif - #ifdef __GPIOH_CLK_ENABLE + #ifdef __HAL_RCC_GPIOH_CLK_ENABLE } else if (gpio == GPIOH) { - __GPIOH_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); #endif - #if defined(GPIOI) && defined(__GPIOI_CLK_ENABLE) + #ifdef __HAL_RCC_GPIOI_CLK_ENABLE } else if (gpio == GPIOI) { - __GPIOI_CLK_ENABLE(); + __HAL_RCC_GPIOI_CLK_ENABLE(); #endif - #if defined(GPIOJ) && defined(__GPIOJ_CLK_ENABLE) + #ifdef __HAL_RCC_GPIOJ_CLK_ENABLE } else if (gpio == GPIOJ) { - __GPIOJ_CLK_ENABLE(); + __HAL_RCC_GPIOJ_CLK_ENABLE(); #endif - #if defined(GPIOK) && defined(__GPIOK_CLK_ENABLE) + #ifdef __HAL_RCC_GPIOK_CLK_ENABLE } else if (gpio == GPIOK) { - __GPIOK_CLK_ENABLE(); + __HAL_RCC_GPIOK_CLK_ENABLE(); #endif } } diff --git a/ports/stm32/pin.c b/ports/stm32/pin.c index ee2d846469..fbd3f00c17 100644 --- a/ports/stm32/pin.c +++ b/ports/stm32/pin.c @@ -376,7 +376,7 @@ STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *self, size_t n_args, const GPIO_InitStructure.Pin = self->pin_mask; GPIO_InitStructure.Mode = mode; GPIO_InitStructure.Pull = pull; - GPIO_InitStructure.Speed = GPIO_SPEED_FAST; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStructure.Alternate = af; HAL_GPIO_Init(self->gpio, &GPIO_InitStructure); diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index fa4a3d40c1..c0bc0f5b64 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -224,7 +224,7 @@ STATIC HAL_StatusTypeDef PYB_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruc /*------------------------------ LSE Configuration -------------------------*/ if ((RCC_OscInitStruct->OscillatorType & RCC_OSCILLATORTYPE_LSE) == RCC_OSCILLATORTYPE_LSE) { // Enable Power Clock - __PWR_CLK_ENABLE(); + __HAL_RCC_PWR_CLK_ENABLE(); HAL_PWR_EnableBkUpAccess(); uint32_t tickstart = HAL_GetTick(); @@ -243,7 +243,7 @@ STATIC HAL_StatusTypeDef PYB_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruc //PWR->CR |= PWR_CR_DBP; // Wait for Backup domain Write protection disable while ((PWR->CR & PWR_CR_DBP) == RESET) { - if (HAL_GetTick() - tickstart > DBP_TIMEOUT_VALUE) { + if (HAL_GetTick() - tickstart > RCC_DBP_TIMEOUT_VALUE) { return HAL_TIMEOUT; } } @@ -399,7 +399,7 @@ STATIC void RTC_CalendarConfig(void) { date.Date = 1; date.WeekDay = RTC_WEEKDAY_THURSDAY; - if(HAL_RTC_SetDate(&RTCHandle, &date, FORMAT_BIN) != HAL_OK) { + if(HAL_RTC_SetDate(&RTCHandle, &date, RTC_FORMAT_BIN) != HAL_OK) { // init error return; } @@ -413,7 +413,7 @@ STATIC void RTC_CalendarConfig(void) { time.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; time.StoreOperation = RTC_STOREOPERATION_RESET; - if (HAL_RTC_SetTime(&RTCHandle, &time, FORMAT_BIN) != HAL_OK) { + if (HAL_RTC_SetTime(&RTCHandle, &time, RTC_FORMAT_BIN) != HAL_OK) { // init error return; } @@ -496,8 +496,8 @@ mp_obj_t pyb_rtc_datetime(size_t n_args, const mp_obj_t *args) { // note: need to call get time then get date to correctly access the registers RTC_DateTypeDef date; RTC_TimeTypeDef time; - HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN); - HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN); + HAL_RTC_GetTime(&RTCHandle, &time, RTC_FORMAT_BIN); + HAL_RTC_GetDate(&RTCHandle, &date, RTC_FORMAT_BIN); mp_obj_t tuple[8] = { mp_obj_new_int(2000 + date.Year), mp_obj_new_int(date.Month), @@ -519,7 +519,7 @@ mp_obj_t pyb_rtc_datetime(size_t n_args, const mp_obj_t *args) { date.Month = mp_obj_get_int(items[1]); date.Date = mp_obj_get_int(items[2]); date.WeekDay = mp_obj_get_int(items[3]); - HAL_RTC_SetDate(&RTCHandle, &date, FORMAT_BIN); + HAL_RTC_SetDate(&RTCHandle, &date, RTC_FORMAT_BIN); RTC_TimeTypeDef time; time.Hours = mp_obj_get_int(items[4]); @@ -529,7 +529,7 @@ mp_obj_t pyb_rtc_datetime(size_t n_args, const mp_obj_t *args) { time.TimeFormat = RTC_HOURFORMAT12_AM; time.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; time.StoreOperation = RTC_STOREOPERATION_SET; - HAL_RTC_SetTime(&RTCHandle, &time, FORMAT_BIN); + HAL_RTC_SetTime(&RTCHandle, &time, RTC_FORMAT_BIN); return mp_const_none; } diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c index 48df9288e4..b328cd239d 100644 --- a/ports/stm32/spi.c +++ b/ports/stm32/spi.c @@ -537,7 +537,7 @@ STATIC void spi_print(const mp_print_t *print, const spi_t *spi_obj, bool legacy mp_printf(print, ", SPI.SLAVE"); } mp_printf(print, ", polarity=%u, phase=%u, bits=%u", spi->Init.CLKPolarity == SPI_POLARITY_LOW ? 0 : 1, spi->Init.CLKPhase == SPI_PHASE_1EDGE ? 0 : 1, spi->Init.DataSize == SPI_DATASIZE_8BIT ? 8 : 16); - if (spi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLED) { + if (spi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) { mp_printf(print, ", crc=0x%x", spi->Init.CRCPolynomial); } } @@ -600,12 +600,12 @@ STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_obj_t *self, size_t n_args, co init->Direction = args[5].u_int; init->NSS = args[7].u_int; - init->TIMode = args[9].u_bool ? SPI_TIMODE_ENABLED : SPI_TIMODE_DISABLED; + init->TIMode = args[9].u_bool ? SPI_TIMODE_ENABLE : SPI_TIMODE_DISABLE; if (args[10].u_obj == mp_const_none) { - init->CRCCalculation = SPI_CRCCALCULATION_DISABLED; + init->CRCCalculation = SPI_CRCCALCULATION_DISABLE; init->CRCPolynomial = 0; } else { - init->CRCCalculation = SPI_CRCCALCULATION_ENABLED; + init->CRCCalculation = SPI_CRCCALCULATION_ENABLE; init->CRCPolynomial = mp_obj_get_int(args[10].u_obj); } @@ -916,7 +916,7 @@ mp_obj_t machine_hard_spi_make_new(const mp_obj_type_t *type, size_t n_args, siz init->Direction = SPI_DIRECTION_2LINES; init->NSS = SPI_NSS_SOFT; init->TIMode = SPI_TIMODE_DISABLED; - init->CRCCalculation = SPI_CRCCALCULATION_DISABLED; + init->CRCCalculation = SPI_CRCCALCULATION_DISABLE; init->CRCPolynomial = 0; // set configurable paramaters diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c index 96a6baa02d..0744c2f593 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -166,7 +166,7 @@ void timer_deinit(void) { // This function inits but does not start the timer void timer_tim5_init(void) { // TIM5 clock enable - __TIM5_CLK_ENABLE(); + __HAL_RCC_TIM5_CLK_ENABLE(); // set up and enable interrupt HAL_NVIC_SetPriority(TIM5_IRQn, IRQ_PRI_TIM5, IRQ_SUBPRI_TIM5); @@ -188,7 +188,7 @@ void timer_tim5_init(void) { // This function inits but does not start the timer TIM_HandleTypeDef *timer_tim6_init(uint freq) { // TIM6 clock enable - __TIM6_CLK_ENABLE(); + __HAL_RCC_TIM6_CLK_ENABLE(); // Timer runs at SystemCoreClock / 2 // Compute the prescaler value so TIM6 triggers at freq-Hz @@ -302,7 +302,7 @@ STATIC uint32_t compute_prescaler_period_from_freq(pyb_timer_obj_t *self, mp_obj STATIC uint32_t compute_period(pyb_timer_obj_t *self) { // In center mode, compare == period corresponds to 100% // In edge mode, compare == (period + 1) corresponds to 100% - uint32_t period = (__HAL_TIM_GetAutoreload(&self->tim) & TIMER_CNT_MASK(self)); + uint32_t period = (__HAL_TIM_GET_AUTORELOAD(&self->tim) & TIMER_CNT_MASK(self)); if (period != 0xffffffff) { if (self->tim.Init.CounterMode == TIM_COUNTERMODE_UP || self->tim.Init.CounterMode == TIM_COUNTERMODE_DOWN) { @@ -439,7 +439,7 @@ STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ mp_printf(print, "Timer(%u)", self->tim_id); } else { uint32_t prescaler = self->tim.Instance->PSC & 0xffff; - uint32_t period = __HAL_TIM_GetAutoreload(&self->tim) & TIMER_CNT_MASK(self); + uint32_t period = __HAL_TIM_GET_AUTORELOAD(&self->tim) & TIMER_CNT_MASK(self); // for efficiency, we compute and print freq as an int (not a float) uint32_t freq = timer_get_source_freq(self->tim_id) / ((prescaler + 1) * (period + 1)); mp_printf(print, "Timer(%u, freq=%u, prescaler=%u, period=%u, mode=%s, div=%u", @@ -554,46 +554,46 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons // enable TIM clock switch (self->tim_id) { - case 1: __TIM1_CLK_ENABLE(); break; - case 2: __TIM2_CLK_ENABLE(); break; - case 3: __TIM3_CLK_ENABLE(); break; - case 4: __TIM4_CLK_ENABLE(); break; - case 5: __TIM5_CLK_ENABLE(); break; + case 1: __HAL_RCC_TIM1_CLK_ENABLE(); break; + case 2: __HAL_RCC_TIM2_CLK_ENABLE(); break; + case 3: __HAL_RCC_TIM3_CLK_ENABLE(); break; + case 4: __HAL_RCC_TIM4_CLK_ENABLE(); break; + case 5: __HAL_RCC_TIM5_CLK_ENABLE(); break; #if defined(TIM6) - case 6: __TIM6_CLK_ENABLE(); break; + case 6: __HAL_RCC_TIM6_CLK_ENABLE(); break; #endif #if defined(TIM7) - case 7: __TIM7_CLK_ENABLE(); break; + case 7: __HAL_RCC_TIM7_CLK_ENABLE(); break; #endif #if defined(TIM8) - case 8: __TIM8_CLK_ENABLE(); break; + case 8: __HAL_RCC_TIM8_CLK_ENABLE(); break; #endif #if defined(TIM9) - case 9: __TIM9_CLK_ENABLE(); break; + case 9: __HAL_RCC_TIM9_CLK_ENABLE(); break; #endif #if defined(TIM10) - case 10: __TIM10_CLK_ENABLE(); break; + case 10: __HAL_RCC_TIM10_CLK_ENABLE(); break; #endif #if defined(TIM11) - case 11: __TIM11_CLK_ENABLE(); break; + case 11: __HAL_RCC_TIM11_CLK_ENABLE(); break; #endif #if defined(TIM12) - case 12: __TIM12_CLK_ENABLE(); break; + case 12: __HAL_RCC_TIM12_CLK_ENABLE(); break; #endif #if defined(TIM13) - case 13: __TIM13_CLK_ENABLE(); break; + case 13: __HAL_RCC_TIM13_CLK_ENABLE(); break; #endif #if defined(TIM14) - case 14: __TIM14_CLK_ENABLE(); break; + case 14: __HAL_RCC_TIM14_CLK_ENABLE(); break; #endif #if defined(TIM15) - case 15: __TIM15_CLK_ENABLE(); break; + case 15: __HAL_RCC_TIM15_CLK_ENABLE(); break; #endif #if defined(TIM16) - case 16: __TIM16_CLK_ENABLE(); break; + case 16: __HAL_RCC_TIM16_CLK_ENABLE(); break; #endif #if defined(TIM17) - case 17: __TIM17_CLK_ENABLE(); break; + case 17: __HAL_RCC_TIM17_CLK_ENABLE(); break; #endif } @@ -1062,7 +1062,7 @@ STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_ma // an interrupt by initializing the timer. __HAL_TIM_DISABLE_IT(&self->tim, TIM_IT_UPDATE); HAL_TIM_Encoder_Init(&self->tim, &enc_config); - __HAL_TIM_SetCounter(&self->tim, 0); + __HAL_TIM_SET_COUNTER(&self->tim, 0); if (self->callback != mp_const_none) { __HAL_TIM_CLEAR_FLAG(&self->tim, TIM_IT_UPDATE); __HAL_TIM_ENABLE_IT(&self->tim, TIM_IT_UPDATE); @@ -1088,7 +1088,7 @@ STATIC mp_obj_t pyb_timer_counter(size_t n_args, const mp_obj_t *args) { return mp_obj_new_int(self->tim.Instance->CNT); } else { // set - __HAL_TIM_SetCounter(&self->tim, mp_obj_get_int(args[1])); + __HAL_TIM_SET_COUNTER(&self->tim, mp_obj_get_int(args[1])); return mp_const_none; } } @@ -1110,7 +1110,7 @@ STATIC mp_obj_t pyb_timer_freq(size_t n_args, const mp_obj_t *args) { if (n_args == 1) { // get uint32_t prescaler = self->tim.Instance->PSC & 0xffff; - uint32_t period = __HAL_TIM_GetAutoreload(&self->tim) & TIMER_CNT_MASK(self); + uint32_t period = __HAL_TIM_GET_AUTORELOAD(&self->tim) & TIMER_CNT_MASK(self); uint32_t source_freq = timer_get_source_freq(self->tim_id); uint32_t divide = ((prescaler + 1) * (period + 1)); #if MICROPY_PY_BUILTINS_FLOAT @@ -1126,7 +1126,7 @@ STATIC mp_obj_t pyb_timer_freq(size_t n_args, const mp_obj_t *args) { uint32_t period; uint32_t prescaler = compute_prescaler_period_from_freq(self, args[1], &period); self->tim.Instance->PSC = prescaler; - __HAL_TIM_SetAutoreload(&self->tim, period); + __HAL_TIM_SET_AUTORELOAD(&self->tim, period); return mp_const_none; } } @@ -1153,10 +1153,10 @@ STATIC mp_obj_t pyb_timer_period(size_t n_args, const mp_obj_t *args) { pyb_timer_obj_t *self = args[0]; if (n_args == 1) { // get - return mp_obj_new_int(__HAL_TIM_GetAutoreload(&self->tim) & TIMER_CNT_MASK(self)); + return mp_obj_new_int(__HAL_TIM_GET_AUTORELOAD(&self->tim) & TIMER_CNT_MASK(self)); } else { // set - __HAL_TIM_SetAutoreload(&self->tim, mp_obj_get_int(args[1]) & TIMER_CNT_MASK(self)); + __HAL_TIM_SET_AUTORELOAD(&self->tim, mp_obj_get_int(args[1]) & TIMER_CNT_MASK(self)); return mp_const_none; } } @@ -1265,10 +1265,10 @@ STATIC mp_obj_t pyb_timer_channel_capture_compare(size_t n_args, const mp_obj_t pyb_timer_channel_obj_t *self = args[0]; if (n_args == 1) { // get - return mp_obj_new_int(__HAL_TIM_GetCompare(&self->timer->tim, TIMER_CHANNEL(self)) & TIMER_CNT_MASK(self->timer)); + return mp_obj_new_int(__HAL_TIM_GET_COMPARE(&self->timer->tim, TIMER_CHANNEL(self)) & TIMER_CNT_MASK(self->timer)); } else { // set - __HAL_TIM_SetCompare(&self->timer->tim, TIMER_CHANNEL(self), mp_obj_get_int(args[1]) & TIMER_CNT_MASK(self->timer)); + __HAL_TIM_SET_COMPARE(&self->timer->tim, TIMER_CHANNEL(self), mp_obj_get_int(args[1]) & TIMER_CNT_MASK(self->timer)); return mp_const_none; } } @@ -1285,12 +1285,12 @@ STATIC mp_obj_t pyb_timer_channel_pulse_width_percent(size_t n_args, const mp_ob uint32_t period = compute_period(self->timer); if (n_args == 1) { // get - uint32_t cmp = __HAL_TIM_GetCompare(&self->timer->tim, TIMER_CHANNEL(self)) & TIMER_CNT_MASK(self->timer); + uint32_t cmp = __HAL_TIM_GET_COMPARE(&self->timer->tim, TIMER_CHANNEL(self)) & TIMER_CNT_MASK(self->timer); return compute_percent_from_pwm_value(period, cmp); } else { // set uint32_t cmp = compute_pwm_value_from_percent(period, args[1]); - __HAL_TIM_SetCompare(&self->timer->tim, TIMER_CHANNEL(self), cmp & TIMER_CNT_MASK(self->timer)); + __HAL_TIM_SET_COMPARE(&self->timer->tim, TIMER_CHANNEL(self), cmp & TIMER_CNT_MASK(self->timer)); return mp_const_none; } } @@ -1365,7 +1365,7 @@ STATIC void timer_handle_irq_channel(pyb_timer_obj_t *tim, uint8_t channel, mp_o uint32_t irq_mask = TIMER_IRQ_MASK(channel); if (__HAL_TIM_GET_FLAG(&tim->tim, irq_mask) != RESET) { - if (__HAL_TIM_GET_ITSTATUS(&tim->tim, irq_mask) != RESET) { + if (__HAL_TIM_GET_IT_SOURCE(&tim->tim, irq_mask) != RESET) { // clear the interrupt __HAL_TIM_CLEAR_IT(&tim->tim, irq_mask); diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index 659aa9943b..1e540e50ac 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -166,7 +166,7 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { irqn = USART1_IRQn; pins[0] = &MICROPY_HW_UART1_TX; pins[1] = &MICROPY_HW_UART1_RX; - __USART1_CLK_ENABLE(); + __HAL_RCC_USART1_CLK_ENABLE(); break; #endif @@ -187,7 +187,7 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { pins[3] = &MICROPY_HW_UART2_CTS; } #endif - __USART2_CLK_ENABLE(); + __HAL_RCC_USART2_CLK_ENABLE(); break; #endif @@ -208,7 +208,7 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { pins[3] = &MICROPY_HW_UART3_CTS; } #endif - __USART3_CLK_ENABLE(); + __HAL_RCC_USART3_CLK_ENABLE(); break; #endif @@ -219,7 +219,7 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { irqn = UART4_IRQn; pins[0] = &MICROPY_HW_UART4_TX; pins[1] = &MICROPY_HW_UART4_RX; - __UART4_CLK_ENABLE(); + __HAL_RCC_UART4_CLK_ENABLE(); break; #endif @@ -230,7 +230,7 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { irqn = UART5_IRQn; pins[0] = &MICROPY_HW_UART5_TX; pins[1] = &MICROPY_HW_UART5_RX; - __UART5_CLK_ENABLE(); + __HAL_RCC_UART5_CLK_ENABLE(); break; #endif @@ -251,7 +251,7 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { pins[3] = &MICROPY_HW_UART6_CTS; } #endif - __USART6_CLK_ENABLE(); + __HAL_RCC_USART6_CLK_ENABLE(); break; #endif @@ -262,7 +262,7 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { irqn = UART7_IRQn; pins[0] = &MICROPY_HW_UART7_TX; pins[1] = &MICROPY_HW_UART7_RX; - __UART7_CLK_ENABLE(); + __HAL_RCC_UART7_CLK_ENABLE(); break; #endif @@ -273,7 +273,7 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { irqn = UART8_IRQn; pins[0] = &MICROPY_HW_UART8_TX; pins[1] = &MICROPY_HW_UART8_RX; - __UART8_CLK_ENABLE(); + __HAL_RCC_UART8_CLK_ENABLE(); break; #endif @@ -801,55 +801,55 @@ STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) { HAL_UART_DeInit(uart); if (uart->Instance == USART1) { HAL_NVIC_DisableIRQ(USART1_IRQn); - __USART1_FORCE_RESET(); - __USART1_RELEASE_RESET(); - __USART1_CLK_DISABLE(); + __HAL_RCC_USART1_FORCE_RESET(); + __HAL_RCC_USART1_RELEASE_RESET(); + __HAL_RCC_USART1_CLK_DISABLE(); } else if (uart->Instance == USART2) { HAL_NVIC_DisableIRQ(USART2_IRQn); - __USART2_FORCE_RESET(); - __USART2_RELEASE_RESET(); - __USART2_CLK_DISABLE(); + __HAL_RCC_USART2_FORCE_RESET(); + __HAL_RCC_USART2_RELEASE_RESET(); + __HAL_RCC_USART2_CLK_DISABLE(); #if defined(USART3) } else if (uart->Instance == USART3) { HAL_NVIC_DisableIRQ(USART3_IRQn); - __USART3_FORCE_RESET(); - __USART3_RELEASE_RESET(); - __USART3_CLK_DISABLE(); + __HAL_RCC_USART3_FORCE_RESET(); + __HAL_RCC_USART3_RELEASE_RESET(); + __HAL_RCC_USART3_CLK_DISABLE(); #endif #if defined(UART4) } else if (uart->Instance == UART4) { HAL_NVIC_DisableIRQ(UART4_IRQn); - __UART4_FORCE_RESET(); - __UART4_RELEASE_RESET(); - __UART4_CLK_DISABLE(); + __HAL_RCC_UART4_FORCE_RESET(); + __HAL_RCC_UART4_RELEASE_RESET(); + __HAL_RCC_UART4_CLK_DISABLE(); #endif #if defined(UART5) } else if (uart->Instance == UART5) { HAL_NVIC_DisableIRQ(UART5_IRQn); - __UART5_FORCE_RESET(); - __UART5_RELEASE_RESET(); - __UART5_CLK_DISABLE(); + __HAL_RCC_UART5_FORCE_RESET(); + __HAL_RCC_UART5_RELEASE_RESET(); + __HAL_RCC_UART5_CLK_DISABLE(); #endif #if defined(UART6) } else if (uart->Instance == USART6) { HAL_NVIC_DisableIRQ(USART6_IRQn); - __USART6_FORCE_RESET(); - __USART6_RELEASE_RESET(); - __USART6_CLK_DISABLE(); + __HAL_RCC_USART6_FORCE_RESET(); + __HAL_RCC_USART6_RELEASE_RESET(); + __HAL_RCC_USART6_CLK_DISABLE(); #endif #if defined(UART7) } else if (uart->Instance == UART7) { HAL_NVIC_DisableIRQ(UART7_IRQn); - __UART7_FORCE_RESET(); - __UART7_RELEASE_RESET(); - __UART7_CLK_DISABLE(); + __HAL_RCC_UART7_FORCE_RESET(); + __HAL_RCC_UART7_RELEASE_RESET(); + __HAL_RCC_UART7_CLK_DISABLE(); #endif #if defined(UART8) } else if (uart->Instance == UART8) { HAL_NVIC_DisableIRQ(UART8_IRQn); - __UART8_FORCE_RESET(); - __UART8_RELEASE_RESET(); - __UART8_CLK_DISABLE(); + __HAL_RCC_UART8_FORCE_RESET(); + __HAL_RCC_UART8_RELEASE_RESET(); + __HAL_RCC_UART8_CLK_DISABLE(); #endif } return mp_const_none; diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index 910c748d88..cdbf14a3f6 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -63,12 +63,12 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) if(hpcd->Instance == USB_OTG_FS) { /* Configure USB FS GPIOs */ - __GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = (GPIO_PIN_11 | GPIO_PIN_12); GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); @@ -119,13 +119,13 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) #if defined(USE_USB_HS_IN_FS) /* Configure USB FS GPIOs */ - __GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); /* Configure DM DP Pins */ GPIO_InitStruct.Pin = (GPIO_PIN_14 | GPIO_PIN_15); GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_OTG_HS_FS; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); @@ -134,7 +134,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) GPIO_InitStruct.Pin = GPIO_PIN_13; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_OTG_HS_FS; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); #endif @@ -144,7 +144,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) GPIO_InitStruct.Pin = GPIO_PIN_12; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_OTG_HS_FS; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); #endif @@ -169,17 +169,17 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) #else // !USE_USB_HS_IN_FS /* Configure USB HS GPIOs */ - __GPIOA_CLK_ENABLE(); - __GPIOB_CLK_ENABLE(); - __GPIOC_CLK_ENABLE(); - __GPIOH_CLK_ENABLE(); - __GPIOI_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); + __HAL_RCC_GPIOI_CLK_ENABLE(); /* CLK */ GPIO_InitStruct.Pin = GPIO_PIN_5; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); @@ -187,7 +187,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) GPIO_InitStruct.Pin = GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); From 6e91ab58063a29fc754ac42ede5612076b2a0199 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 13 Feb 2018 15:53:08 +1100 Subject: [PATCH 291/828] stm32/spi: Further updates to use newer versions of HAL names. --- ports/stm32/spi.c | 50 +++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c index b328cd239d..6a6a412f74 100644 --- a/ports/stm32/spi.c +++ b/ports/stm32/spi.c @@ -257,7 +257,7 @@ void spi_init(const spi_t *self, bool enable_nss_pin) { #endif pins[3] = &MICROPY_HW_SPI1_MOSI; // enable the SPI clock - __SPI1_CLK_ENABLE(); + __HAL_RCC_SPI1_CLK_ENABLE(); #endif #if defined(MICROPY_HW_SPI2_SCK) } else if (spi->Instance == SPI2) { @@ -270,7 +270,7 @@ void spi_init(const spi_t *self, bool enable_nss_pin) { #endif pins[3] = &MICROPY_HW_SPI2_MOSI; // enable the SPI clock - __SPI2_CLK_ENABLE(); + __HAL_RCC_SPI2_CLK_ENABLE(); #endif #if defined(MICROPY_HW_SPI3_SCK) } else if (spi->Instance == SPI3) { @@ -283,7 +283,7 @@ void spi_init(const spi_t *self, bool enable_nss_pin) { #endif pins[3] = &MICROPY_HW_SPI3_MOSI; // enable the SPI clock - __SPI3_CLK_ENABLE(); + __HAL_RCC_SPI3_CLK_ENABLE(); #endif #if defined(MICROPY_HW_SPI4_SCK) } else if (spi->Instance == SPI4) { @@ -296,7 +296,7 @@ void spi_init(const spi_t *self, bool enable_nss_pin) { #endif pins[3] = &MICROPY_HW_SPI4_MOSI; // enable the SPI clock - __SPI4_CLK_ENABLE(); + __HAL_RCC_SPI4_CLK_ENABLE(); #endif #if defined(MICROPY_HW_SPI5_SCK) } else if (spi->Instance == SPI5) { @@ -309,7 +309,7 @@ void spi_init(const spi_t *self, bool enable_nss_pin) { #endif pins[3] = &MICROPY_HW_SPI5_MOSI; // enable the SPI clock - __SPI5_CLK_ENABLE(); + __HAL_RCC_SPI5_CLK_ENABLE(); #endif #if defined(MICROPY_HW_SPI6_SCK) } else if (spi->Instance == SPI6) { @@ -322,7 +322,7 @@ void spi_init(const spi_t *self, bool enable_nss_pin) { #endif pins[3] = &MICROPY_HW_SPI6_MOSI; // enable the SPI clock - __SPI6_CLK_ENABLE(); + __HAL_RCC_SPI6_CLK_ENABLE(); #endif } else { // SPI does not exist for this board (shouldn't get here, should be checked by caller) @@ -361,39 +361,39 @@ void spi_deinit(const spi_t *spi_obj) { if (0) { #if defined(MICROPY_HW_SPI1_SCK) } else if (spi->Instance == SPI1) { - __SPI1_FORCE_RESET(); - __SPI1_RELEASE_RESET(); - __SPI1_CLK_DISABLE(); + __HAL_RCC_SPI1_FORCE_RESET(); + __HAL_RCC_SPI1_RELEASE_RESET(); + __HAL_RCC_SPI1_CLK_DISABLE(); #endif #if defined(MICROPY_HW_SPI2_SCK) } else if (spi->Instance == SPI2) { - __SPI2_FORCE_RESET(); - __SPI2_RELEASE_RESET(); - __SPI2_CLK_DISABLE(); + __HAL_RCC_SPI2_FORCE_RESET(); + __HAL_RCC_SPI2_RELEASE_RESET(); + __HAL_RCC_SPI2_CLK_DISABLE(); #endif #if defined(MICROPY_HW_SPI3_SCK) } else if (spi->Instance == SPI3) { - __SPI3_FORCE_RESET(); - __SPI3_RELEASE_RESET(); - __SPI3_CLK_DISABLE(); + __HAL_RCC_SPI3_FORCE_RESET(); + __HAL_RCC_SPI3_RELEASE_RESET(); + __HAL_RCC_SPI3_CLK_DISABLE(); #endif #if defined(MICROPY_HW_SPI4_SCK) } else if (spi->Instance == SPI4) { - __SPI4_FORCE_RESET(); - __SPI4_RELEASE_RESET(); - __SPI4_CLK_DISABLE(); + __HAL_RCC_SPI4_FORCE_RESET(); + __HAL_RCC_SPI4_RELEASE_RESET(); + __HAL_RCC_SPI4_CLK_DISABLE(); #endif #if defined(MICROPY_HW_SPI5_SCK) } else if (spi->Instance == SPI5) { - __SPI5_FORCE_RESET(); - __SPI5_RELEASE_RESET(); - __SPI5_CLK_DISABLE(); + __HAL_RCC_SPI5_FORCE_RESET(); + __HAL_RCC_SPI5_RELEASE_RESET(); + __HAL_RCC_SPI5_CLK_DISABLE(); #endif #if defined(MICROPY_HW_SPI6_SCK) } else if (spi->Instance == SPI6) { - __SPI6_FORCE_RESET(); - __SPI6_RELEASE_RESET(); - __SPI6_CLK_DISABLE(); + __HAL_RCC_SPI6_FORCE_RESET(); + __HAL_RCC_SPI6_RELEASE_RESET(); + __HAL_RCC_SPI6_CLK_DISABLE(); #endif } } @@ -915,7 +915,7 @@ mp_obj_t machine_hard_spi_make_new(const mp_obj_type_t *type, size_t n_args, siz // these parameters are not currently configurable init->Direction = SPI_DIRECTION_2LINES; init->NSS = SPI_NSS_SOFT; - init->TIMode = SPI_TIMODE_DISABLED; + init->TIMode = SPI_TIMODE_DISABLE; init->CRCCalculation = SPI_CRCCALCULATION_DISABLE; init->CRCPolynomial = 0; From 8aad22fdca757fd7135fb2f68ff8023a1f5bebc3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 13 Feb 2018 15:53:39 +1100 Subject: [PATCH 292/828] stm32/timer: Support MCUs that don't have TIM4 and/or TIM5. --- ports/stm32/timer.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c index 0744c2f593..bac63ae920 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -162,6 +162,7 @@ void timer_deinit(void) { } } +#if defined(TIM5) // TIM5 is set-up for the servo controller // This function inits but does not start the timer void timer_tim5_init(void) { @@ -181,6 +182,7 @@ void timer_tim5_init(void) { HAL_TIM_PWM_Init(&TIM5_Handle); } +#endif #if defined(TIM6) // Init TIM6 with a counter-overflow at the given frequency (given in Hz) @@ -557,8 +559,12 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons case 1: __HAL_RCC_TIM1_CLK_ENABLE(); break; case 2: __HAL_RCC_TIM2_CLK_ENABLE(); break; case 3: __HAL_RCC_TIM3_CLK_ENABLE(); break; + #if defined(TIM4) case 4: __HAL_RCC_TIM4_CLK_ENABLE(); break; + #endif + #if defined(TIM5) case 5: __HAL_RCC_TIM5_CLK_ENABLE(); break; + #endif #if defined(TIM6) case 6: __HAL_RCC_TIM6_CLK_ENABLE(); break; #endif @@ -646,8 +652,12 @@ STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = { #endif TIM_ENTRY(2, TIM2_IRQn), TIM_ENTRY(3, TIM3_IRQn), + #if defined(TIM4) TIM_ENTRY(4, TIM4_IRQn), + #endif + #if defined(TIM5) TIM_ENTRY(5, TIM5_IRQn), + #endif #if defined(TIM6) TIM_ENTRY(6, TIM6_DAC_IRQn), #endif @@ -1049,8 +1059,12 @@ STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_ma if (self->tim.Instance != TIM1 && self->tim.Instance != TIM2 && self->tim.Instance != TIM3 + #if defined(TIM4) && self->tim.Instance != TIM4 + #endif + #if defined(TIM5) && self->tim.Instance != TIM5 + #endif #if defined(TIM8) && self->tim.Instance != TIM8 #endif From 5c320bd0b093f44cad19046d84a63e5ed4e7fc87 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 13 Feb 2018 18:51:08 +1100 Subject: [PATCH 293/828] stm32: Introduce MICROPY_HW_ENABLE_USB and clean up USB config. This patch allows to completely compile-out support for USB, and no-USB is now the default. If a board wants to enable USB it should define: #define MICROPY_HW_ENABLE_USB (1) And then one or more of the following to select the USB PHY: #define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_HS (1) #define MICROPY_HW_USB_HS_IN_FS (1) --- ports/stm32/main.c | 12 ++++---- ports/stm32/modmachine.c | 2 ++ ports/stm32/modpyb.c | 2 ++ ports/stm32/mpconfigboard_common.h | 11 ++++---- ports/stm32/mphalport.c | 7 ++++- ports/stm32/stm32_it.c | 12 ++++---- ports/stm32/stm32_it.h | 4 --- ports/stm32/usb.c | 25 ++++++----------- ports/stm32/usbd_conf.c | 28 +++++++++---------- .../stm32/usbdev/class/inc/usbd_cdc_msc_hid.h | 9 ++++-- 10 files changed, 57 insertions(+), 55 deletions(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 92a6100c98..cb3bdf7496 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -308,14 +308,14 @@ STATIC bool init_sdcard_fs(void) { } } - #if defined(USE_DEVICE_MODE) + #if MICROPY_HW_ENABLE_USB if (pyb_usb_storage_medium == PYB_USB_STORAGE_MEDIUM_NONE) { // if no USB MSC medium is selected then use the SD card pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_SDCARD; } #endif - #if defined(USE_DEVICE_MODE) + #if MICROPY_HW_ENABLE_USB // only use SD card as current directory if that's what the USB medium is if (pyb_usb_storage_medium == PYB_USB_STORAGE_MEDIUM_SDCARD) #endif @@ -539,7 +539,9 @@ soft_reset: can_init0(); #endif + #if MICROPY_HW_ENABLE_USB pyb_usb_init0(); + #endif // Initialise the local flash filesystem. // Create it if needed, mount in on /flash, and set it as current dir. @@ -556,7 +558,7 @@ soft_reset: } #endif - #if defined(USE_DEVICE_MODE) + #if MICROPY_HW_ENABLE_USB // if the SD card isn't used as the USB MSC medium then use the internal flash if (pyb_usb_storage_medium == PYB_USB_STORAGE_MEDIUM_NONE) { pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_FLASH; @@ -607,12 +609,12 @@ soft_reset: // or whose initialisation can be safely deferred until after running // boot.py. -#if defined(USE_DEVICE_MODE) + #if MICROPY_HW_ENABLE_USB // init USB device to default setting if it was not already configured if (!(pyb_usb_flags & PYB_USB_FLAG_USB_MODE_CALLED)) { pyb_usb_dev_init(USBD_VID, USBD_PID_CDC_MSC, USBD_MODE_CDC_MSC, NULL); } -#endif + #endif #if MICROPY_HW_HAS_MMA7660 // MMA accel: init and reset diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index 363fbe3219..5a499e3da6 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -204,7 +204,9 @@ MP_DEFINE_CONST_FUN_OBJ_0(machine_soft_reset_obj, machine_soft_reset); // Activate the bootloader without BOOT* pins. STATIC NORETURN mp_obj_t machine_bootloader(void) { + #if MICROPY_HW_ENABLE_USB pyb_usb_dev_deinit(); + #endif storage_flush(); HAL_RCC_DeInit(); diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c index 970b5b954e..2192b5fcfd 100644 --- a/ports/stm32/modpyb.c +++ b/ports/stm32/modpyb.c @@ -151,6 +151,7 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_main), MP_ROM_PTR(&pyb_main_obj) }, { MP_ROM_QSTR(MP_QSTR_repl_uart), MP_ROM_PTR(&pyb_repl_uart_obj) }, + #if MICROPY_HW_ENABLE_USB { MP_ROM_QSTR(MP_QSTR_usb_mode), MP_ROM_PTR(&pyb_usb_mode_obj) }, { MP_ROM_QSTR(MP_QSTR_hid_mouse), MP_ROM_PTR(&pyb_usb_hid_mouse_obj) }, { MP_ROM_QSTR(MP_QSTR_hid_keyboard), MP_ROM_PTR(&pyb_usb_hid_keyboard_obj) }, @@ -159,6 +160,7 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { // these 2 are deprecated; use USB_VCP.isconnected and USB_HID.send instead { MP_ROM_QSTR(MP_QSTR_have_cdc), MP_ROM_PTR(&pyb_have_cdc_obj) }, { MP_ROM_QSTR(MP_QSTR_hid), MP_ROM_PTR(&pyb_hid_send_report_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_millis), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, { MP_ROM_QSTR(MP_QSTR_elapsed_millis), MP_ROM_PTR(&pyb_elapsed_millis_obj) }, diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 1e3d6913b4..32b69cc788 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -50,6 +50,11 @@ #define MICROPY_HW_ENABLE_CAN (0) #endif +// Whether to enable USB support +#ifndef MICROPY_HW_ENABLE_USB +#define MICROPY_HW_ENABLE_USB (0) +#endif + // Whether to enable the PA0-PA3 servo driver, exposed as pyb.Servo #ifndef MICROPY_HW_ENABLE_SERVO #define MICROPY_HW_ENABLE_SERVO (0) @@ -106,11 +111,5 @@ #define MICROPY_HW_ENABLE_HW_I2C (0) #endif -// USB configuration -// see stm32f4XX_hal_conf.h USE_USB_FS & USE_USB_HS -// at the moment only USB_FS is supported -#define USE_DEVICE_MODE -//#define USE_HOST_MODE - // Pin definition header file #define MICROPY_PIN_DEFS_PORT_H "pin_defs_stm32.h" diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c index 2252e4f577..74906311eb 100644 --- a/ports/stm32/mphalport.c +++ b/ports/stm32/mphalport.c @@ -33,10 +33,13 @@ int mp_hal_stdin_rx_chr(void) { #endif #endif + #if MICROPY_HW_ENABLE_USB byte c; if (usb_vcp_recv_byte(&c) != 0) { return c; - } else if (MP_STATE_PORT(pyb_stdio_uart) != NULL && uart_rx_any(MP_STATE_PORT(pyb_stdio_uart))) { + } + #endif + if (MP_STATE_PORT(pyb_stdio_uart) != NULL && uart_rx_any(MP_STATE_PORT(pyb_stdio_uart))) { return uart_rx_char(MP_STATE_PORT(pyb_stdio_uart)); } int dupterm_c = mp_uos_dupterm_rx_chr(); @@ -58,9 +61,11 @@ void mp_hal_stdout_tx_strn(const char *str, size_t len) { #if 0 && defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD lcd_print_strn(str, len); #endif + #if MICROPY_HW_ENABLE_USB if (usb_vcp_is_enabled()) { usb_vcp_send_strn(str, len); } + #endif mp_uos_dupterm_tx_strn(str, len); } diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index f1ac9b6b85..f933250b1f 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -143,9 +143,11 @@ void HardFault_C_Handler(ExceptionRegisters_t *regs) { NVIC_SystemReset(); } + #if MICROPY_HW_ENABLE_USB // We need to disable the USB so it doesn't try to write data out on // the VCP and then block indefinitely waiting for the buffer to drain. pyb_usb_flags = 0; + #endif mp_hal_stdout_tx_str("HardFault\r\n"); @@ -337,14 +339,14 @@ void SysTick_Handler(void) { * @param None * @retval None */ -#if defined(USE_USB_FS) +#if MICROPY_HW_USB_FS void OTG_FS_IRQHandler(void) { IRQ_ENTER(OTG_FS_IRQn); HAL_PCD_IRQHandler(&pcd_fs_handle); IRQ_EXIT(OTG_FS_IRQn); } #endif -#if defined(USE_USB_HS) +#if MICROPY_HW_USB_HS void OTG_HS_IRQHandler(void) { IRQ_ENTER(OTG_HS_IRQn); HAL_PCD_IRQHandler(&pcd_hs_handle); @@ -352,7 +354,7 @@ void OTG_HS_IRQHandler(void) { } #endif -#if defined(USE_USB_FS) || defined(USE_USB_HS) +#if MICROPY_HW_USB_FS || MICROPY_HW_USB_HS /** * @brief This function handles USB OTG Common FS/HS Wakeup functions. * @param *pcd_handle for FS or HS @@ -393,7 +395,7 @@ STATIC void OTG_CMD_WKUP_Handler(PCD_HandleTypeDef *pcd_handle) { } #endif -#if defined(USE_USB_FS) +#if MICROPY_HW_USB_FS /** * @brief This function handles USB OTG FS Wakeup IRQ Handler. * @param None @@ -411,7 +413,7 @@ void OTG_FS_WKUP_IRQHandler(void) { } #endif -#if defined(USE_USB_HS) +#if MICROPY_HW_USB_HS /** * @brief This function handles USB OTG HS Wakeup IRQ Handler. * @param None diff --git a/ports/stm32/stm32_it.h b/ports/stm32/stm32_it.h index b498dee8da..0f200fb6fe 100644 --- a/ports/stm32/stm32_it.h +++ b/ports/stm32/stm32_it.h @@ -76,11 +76,7 @@ void SVC_Handler(void); void DebugMon_Handler(void); void PendSV_Handler(void); void SysTick_Handler(void); -#ifdef USE_USB_FS void OTG_FS_IRQHandler(void); -#endif -#ifdef USE_USB_HS void OTG_HS_IRQHandler(void); -#endif #endif // MICROPY_INCLUDED_STMHAL_STM32_IT_H diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index e134781b45..b0bdb3a087 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -42,11 +42,13 @@ #include "bufhelper.h" #include "usb.h" +#if MICROPY_HW_ENABLE_USB + // Work out which USB device to use as the main one (the one with the REPL) #if !defined(MICROPY_HW_USB_MAIN_DEV) -#if defined(USE_USB_FS) +#if defined(MICROPY_HW_USB_FS) #define MICROPY_HW_USB_MAIN_DEV (USB_PHY_FS_ID) -#elif defined(USE_USB_HS) && defined(USE_USB_HS_IN_FS) +#elif defined(MICROPY_HW_USB_HS) && defined(MICROPY_HW_USB_HS_IN_FS) #define MICROPY_HW_USB_MAIN_DEV (USB_PHY_HS_ID) #else #error Unable to determine proper MICROPY_HW_USB_MAIN_DEV to use @@ -64,10 +66,8 @@ typedef struct _usb_device_t { usbd_hid_itf_t usbd_hid_itf; } usb_device_t; -#ifdef USE_DEVICE_MODE usb_device_t usb_device; pyb_usb_storage_medium_t pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_NONE; -#endif // predefined hid mouse data STATIC const mp_obj_str_t pyb_usb_hid_mouse_desc_obj = { @@ -113,7 +113,6 @@ void pyb_usb_init0(void) { } bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_HID_ModeInfoTypeDef *hid_info) { -#ifdef USE_DEVICE_MODE bool high_speed = (mode & USBD_MODE_HIGH_SPEED) != 0; mode &= 0x7f; usb_device_t *usb_dev = &usb_device; @@ -153,7 +152,6 @@ bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_H USBD_LL_Start(usbd); usb_dev->enabled = true; } -#endif return true; } @@ -175,11 +173,9 @@ int usb_vcp_recv_byte(uint8_t *c) { } void usb_vcp_send_strn(const char *str, int len) { -#ifdef USE_DEVICE_MODE if (usb_device.enabled) { usbd_cdc_tx_always(&usb_device.usbd_cdc_itf, (const uint8_t*)str, len); } -#endif } /******************************************************************************/ @@ -226,7 +222,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * if (n_args == 0) { #if defined(USE_HOST_MODE) return MP_OBJ_NEW_QSTR(MP_QSTR_host); - #elif defined(USE_DEVICE_MODE) + #else uint8_t mode = USBD_GetMode(&usb_device.usbd_cdc_msc_hid_state); switch (mode) { case USBD_MODE_CDC: @@ -257,9 +253,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * // check if user wants to disable the USB if (args[0].u_obj == mp_const_none) { // disable usb - #if defined(USE_DEVICE_MODE) pyb_usb_dev_deinit(); - #endif return mp_const_none; } @@ -276,7 +270,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * goto bad_mode; } -#elif defined(USE_DEVICE_MODE) +#else // hardware configured for USB device mode @@ -339,9 +333,6 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * goto bad_mode; } -#else - // hardware not configured for USB - goto bad_mode; #endif return mp_const_none; @@ -619,7 +610,6 @@ STATIC mp_obj_t pyb_usb_hid_recv(size_t n_args, const mp_obj_t *args, mp_map_t * STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_hid_recv_obj, 1, pyb_usb_hid_recv); STATIC mp_obj_t pyb_usb_hid_send(mp_obj_t self_in, mp_obj_t report_in) { -#ifdef USE_DEVICE_MODE pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_buffer_info_t bufinfo; byte temp_buf[8]; @@ -643,7 +633,6 @@ STATIC mp_obj_t pyb_usb_hid_send(mp_obj_t self_in, mp_obj_t report_in) { } else { return mp_obj_new_int(0); } -#endif return mp_const_none; } @@ -757,3 +746,5 @@ void USR_KEYBRD_ProcessData(uint8_t pbuf) { } #endif // USE_HOST_MODE + +#endif // MICROPY_HW_ENABLE_USB diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index cdbf14a3f6..e8031c49b3 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -39,10 +39,10 @@ /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ -#ifdef USE_USB_FS +#if MICROPY_HW_USB_FS PCD_HandleTypeDef pcd_fs_handle; #endif -#ifdef USE_USB_HS +#if MICROPY_HW_USB_HS PCD_HandleTypeDef pcd_hs_handle; #endif /* Private function prototypes -----------------------------------------------*/ @@ -113,10 +113,10 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) /* Enable USBFS Interrupt */ HAL_NVIC_EnableIRQ(OTG_FS_IRQn); } -#if defined(USE_USB_HS) +#if MICROPY_HW_USB_HS else if(hpcd->Instance == USB_OTG_HS) { -#if defined(USE_USB_HS_IN_FS) +#if MICROPY_HW_USB_HS_IN_FS /* Configure USB FS GPIOs */ __HAL_RCC_GPIOB_CLK_ENABLE(); @@ -166,7 +166,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) __HAL_RCC_USB_OTG_HS_CLK_ENABLE(); -#else // !USE_USB_HS_IN_FS +#else // !MICROPY_HW_USB_HS_IN_FS /* Configure USB HS GPIOs */ __HAL_RCC_GPIOA_CLK_ENABLE(); @@ -223,7 +223,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) /* Enable USB HS Clocks */ __USB_OTG_HS_CLK_ENABLE(); __USB_OTG_HS_ULPI_CLK_ENABLE(); -#endif // !USE_USB_HS_IN_FS +#endif // !MICROPY_HW_USB_HS_IN_FS /* Set USBHS Interrupt to the lowest priority */ HAL_NVIC_SetPriority(OTG_HS_IRQn, IRQ_PRI_OTG_HS, IRQ_SUBPRI_OTG_HS); @@ -231,7 +231,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) /* Enable USBHS Interrupt */ HAL_NVIC_EnableIRQ(OTG_HS_IRQn); } -#endif // USE_USB_HS +#endif // MICROPY_HW_USB_HS } /** * @brief DeInitializes the PCD MSP. @@ -246,7 +246,7 @@ void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd) __USB_OTG_FS_CLK_DISABLE(); __SYSCFG_CLK_DISABLE(); } - #if defined(USE_USB_HS) + #if MICROPY_HW_USB_HS else if(hpcd->Instance == USB_OTG_HS) { /* Disable USB FS Clocks */ @@ -410,7 +410,7 @@ void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) */ USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev, int high_speed) { -#if defined(USE_USB_FS) +#if MICROPY_HW_USB_FS if (pdev->id == USB_PHY_FS_ID) { /*Set LL Driver parameters */ @@ -445,10 +445,10 @@ if (pdev->id == USB_PHY_FS_ID) HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 0x40); } #endif -#if defined(USE_USB_HS) +#if MICROPY_HW_USB_HS if (pdev->id == USB_PHY_HS_ID) { -#if defined(USE_USB_HS_IN_FS) +#if MICROPY_HW_USB_HS_IN_FS /*Set LL Driver parameters */ pcd_hs_handle.Instance = USB_OTG_HS; pcd_hs_handle.Init.dev_endpoints = 4; @@ -484,7 +484,7 @@ if (pdev->id == USB_PHY_HS_ID) HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 0x100); HAL_PCD_SetTxFiFo(&pcd_hs_handle, 2, 0x20); HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 0xc0); -#else // !defined(USE_USB_HS_IN_FS) +#else // !MICROPY_HW_USB_HS_IN_FS /*Set LL Driver parameters */ pcd_hs_handle.Instance = USB_OTG_HS; pcd_hs_handle.Init.dev_endpoints = 6; @@ -513,9 +513,9 @@ if (pdev->id == USB_PHY_HS_ID) HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 0x80); HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 0x174); -#endif // !USE_USB_HS_IN_FS +#endif // !MICROPY_HW_USB_HS_IN_FS } -#endif // USE_USB_HS +#endif // MICROPY_HW_USB_HS return USBD_OK; } diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h index 600d863790..2177127019 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -5,11 +5,14 @@ #include "usbd_msc_bot.h" #include "usbd_msc_scsi.h" #include "usbd_ioreq.h" -#include STM32_HAL_H + +// These are included to get direct access the MICROPY_HW_USB_xxx config +#include "mpconfigboard.h" +#include "mpconfigboard_common.h" // Work out if we should support USB high-speed device mode -#if defined(USE_USB_HS) \ - && (!defined(USE_USB_HS_IN_FS) || defined(STM32F723xx) || defined(STM32F733xx)) +#if MICROPY_HW_USB_HS \ + && (!MICROPY_HW_USB_HS_IN_FS || defined(STM32F723xx) || defined(STM32F733xx)) #define USBD_SUPPORT_HS_MODE (1) #else #define USBD_SUPPORT_HS_MODE (0) From d9b9fbc41ae202cf9426cc1ae7514d230cc5c8d0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 13 Feb 2018 18:56:12 +1100 Subject: [PATCH 294/828] lib/utils/pyexec: Update to work with new MICROPY_HW_ENABLE_USB option. --- lib/utils/pyexec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index 1e99aa649a..0522de7973 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -35,7 +35,7 @@ #include "py/gc.h" #include "py/frozenmod.h" #include "py/mphal.h" -#if defined(USE_DEVICE_MODE) +#if MICROPY_HW_ENABLE_USB #include "irq.h" #include "usb.h" #endif @@ -406,7 +406,7 @@ friendly_repl_reset: for (;;) { input_restart: - #if defined(USE_DEVICE_MODE) + #if MICROPY_HW_ENABLE_USB if (usb_vcp_is_enabled()) { // If the user gets to here and interrupts are disabled then // they'll never see the prompt, traceback etc. The USB REPL needs From 34911f1a57296bda532e2460e28bd351198e1e63 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 13 Feb 2018 18:57:01 +1100 Subject: [PATCH 295/828] stm32/boards: Update all boards to work with new USB configuration. --- ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h | 4 ++++ ports/stm32/boards/B_L475E_IOT01A/stm32l4xx_hal_conf.h | 1 - ports/stm32/boards/CERB40/mpconfigboard.h | 2 ++ ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h | 2 -- ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h | 4 ++++ ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h | 2 -- ports/stm32/boards/HYDRABUS/mpconfigboard.h | 2 ++ ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h | 2 -- ports/stm32/boards/LIMIFROG/mpconfigboard.h | 2 ++ ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h | 1 - ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h | 4 +++- ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h | 2 -- ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h | 4 ---- ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h | 4 ---- ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h | 2 ++ ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h | 2 -- ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h | 4 ---- ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h | 2 ++ ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h | 2 -- ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h | 2 ++ ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h | 2 -- ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h | 4 ++++ ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h | 1 - ports/stm32/boards/OLIMEX_E407/mpconfigboard.h | 2 ++ ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h | 2 -- ports/stm32/boards/PYBLITEV10/mpconfigboard.h | 2 ++ ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h | 2 -- ports/stm32/boards/PYBV10/mpconfigboard.h | 2 ++ ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h | 2 -- ports/stm32/boards/PYBV11/mpconfigboard.h | 2 ++ ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h | 2 -- ports/stm32/boards/PYBV3/mpconfigboard.h | 2 ++ ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h | 2 -- ports/stm32/boards/PYBV4/mpconfigboard.h | 2 ++ ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h | 2 -- ports/stm32/boards/STM32F411DISC/mpconfigboard.h | 2 ++ ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h | 2 -- ports/stm32/boards/STM32F429DISC/mpconfigboard.h | 3 +++ ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h | 3 --- ports/stm32/boards/STM32F439/mpconfigboard.h | 6 +++++- ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h | 2 -- ports/stm32/boards/STM32F4DISC/mpconfigboard.h | 2 ++ ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h | 2 -- ports/stm32/boards/STM32F769DISC/mpconfigboard.h | 3 +++ ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h | 3 --- ports/stm32/boards/STM32F7DISC/mpconfigboard.h | 3 ++- ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h | 2 -- ports/stm32/boards/STM32L476DISC/mpconfigboard.h | 2 ++ ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h | 1 - 49 files changed, 58 insertions(+), 59 deletions(-) diff --git a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h index cc4f36526a..3ab3d5fa17 100644 --- a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h +++ b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h @@ -4,6 +4,7 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_USB (1) // MSI is used and is 4MHz #define MICROPY_HW_CLK_PLLM (1) @@ -65,3 +66,6 @@ #define MICROPY_HW_LED2 (pin_B14) // green #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config +#define MICROPY_HW_USB_FS (1) diff --git a/ports/stm32/boards/B_L475E_IOT01A/stm32l4xx_hal_conf.h b/ports/stm32/boards/B_L475E_IOT01A/stm32l4xx_hal_conf.h index 9348e06790..6bfb28118a 100644 --- a/ports/stm32/boards/B_L475E_IOT01A/stm32l4xx_hal_conf.h +++ b/ports/stm32/boards/B_L475E_IOT01A/stm32l4xx_hal_conf.h @@ -45,7 +45,6 @@ extern "C" { #endif -#define USE_USB_FS /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ diff --git a/ports/stm32/boards/CERB40/mpconfigboard.h b/ports/stm32/boards/CERB40/mpconfigboard.h index 444185ca01..fdc7c01205 100644 --- a/ports/stm32/boards/CERB40/mpconfigboard.h +++ b/ports/stm32/boards/CERB40/mpconfigboard.h @@ -6,6 +6,7 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 12MHz #define MICROPY_HW_CLK_PLLM (12) @@ -54,5 +55,6 @@ // The Cerb40 has No SDCard // USB config +#define MICROPY_HW_USB_FS (1) //#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) //#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h b/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h index d6aca705cf..e71ba33697 100644 --- a/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h index d3ae825b80..53c7f3cd50 100644 --- a/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h +++ b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h @@ -10,6 +10,7 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_USB (1) #define MICROPY_HW_ENABLE_SERVO (1) // Pico has an 8 MHz HSE and the F401 does 84 MHz max @@ -62,3 +63,6 @@ #define MICROPY_HW_LED4 (pin_B12) // green #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config +#define MICROPY_HW_USB_FS (1) diff --git a/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h b/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h index 11a396b73e..d27e2e9ef0 100644 --- a/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/HYDRABUS/mpconfigboard.h b/ports/stm32/boards/HYDRABUS/mpconfigboard.h index 4d5b12866b..2e73d3ec88 100644 --- a/ports/stm32/boards/HYDRABUS/mpconfigboard.h +++ b/ports/stm32/boards/HYDRABUS/mpconfigboard.h @@ -6,6 +6,7 @@ #define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) @@ -69,4 +70,5 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (1) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h b/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h index d3df51c101..daf9b63cec 100644 --- a/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/LIMIFROG/mpconfigboard.h b/ports/stm32/boards/LIMIFROG/mpconfigboard.h index dfa159fc7c..d27c2e66ef 100644 --- a/ports/stm32/boards/LIMIFROG/mpconfigboard.h +++ b/ports/stm32/boards/LIMIFROG/mpconfigboard.h @@ -5,6 +5,7 @@ #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_USB (1) #define MICROPY_BOARD_EARLY_INIT LIMIFROG_board_early_init void LIMIFROG_board_early_init(void); @@ -50,4 +51,5 @@ void LIMIFROG_board_early_init(void); #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config +#define MICROPY_HW_USB_FS (1) // #define MICROPY_HW_USB_OTG_ID_PIN (pin_C12) // This is not the official ID Pin which should be PA10 diff --git a/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h b/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h index 9348e06790..6bfb28118a 100644 --- a/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h +++ b/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h @@ -45,7 +45,6 @@ extern "C" { #endif -#define USE_USB_FS /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h index fc83d769e1..3125767562 100644 --- a/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h +++ b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h @@ -9,6 +9,7 @@ // we can turn this on. #define MICROPY_HW_HAS_SDCARD (0) #define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_USB (1) #define MICROPY_HW_ENABLE_SERVO (1) void NETDUINO_PLUS_2_board_early_init(void); @@ -62,5 +63,6 @@ void NETDUINO_PLUS_2_board_early_init(void); #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) -// USB VBUS detect pin +// USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h b/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h index 42c2c4e9be..4cb5a83e45 100644 --- a/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h index f4db4cb631..daf9b63cec 100644 --- a/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h @@ -46,10 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -// This board doesn't really have USB, but the stm32 codebase doesn't build -// without some USB defined, so we leave this on for now. -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h index 0c424888f8..8f0b663811 100644 --- a/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h @@ -46,10 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -// This board doesn't really have USB, but the stm32 codebase doesn't build -// without some USB defined, so we leave this on for now. -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h index 4df87f0602..ae7f822256 100644 --- a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h @@ -6,6 +6,7 @@ #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) @@ -72,5 +73,6 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config (CN13 - USB OTG FS) +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h index d121b18c5e..5b5a8a3e43 100644 --- a/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h index 487ca009f2..245fb9a06a 100644 --- a/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h @@ -46,10 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -// This board doesn't really have USB, but the stm32 codebase doesn't build -// without some USB defined, so we leave this on for now. -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h index 0fe6030bb3..42beb4d9bf 100644 --- a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h @@ -12,6 +12,7 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz // VCOClock = HSE * PLLN / PLLM = 8 MHz * 216 / 4 = 432 MHz @@ -66,5 +67,6 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config (CN13 - USB OTG FS) +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h index e1aa4578d5..a019ee4ce9 100644 --- a/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h index c3fd016c19..4f9d41f1b1 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h @@ -12,6 +12,7 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 25MHz // VCOClock = HSE * PLLN / PLLM = 25 MHz * 432 / 25 = 432 MHz @@ -66,5 +67,6 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config (CN13 - USB OTG FS) +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h index e1aa4578d5..a019ee4ce9 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h index 806f8207d0..0d5dab3945 100644 --- a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h @@ -4,6 +4,7 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_USB (1) // MSI is used and is 4MHz #define MICROPY_HW_CLK_PLLM (1) @@ -49,3 +50,6 @@ #define MICROPY_HW_LED1 (pin_A5) // Green LD2 LED on Nucleo #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config +#define MICROPY_HW_USB_FS (1) diff --git a/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h index 9348e06790..6bfb28118a 100755 --- a/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h @@ -45,7 +45,6 @@ extern "C" { #endif -#define USE_USB_FS /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ diff --git a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h index c1e67e3d86..1bdb25a9ea 100644 --- a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h +++ b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h @@ -8,6 +8,7 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 12MHz #define MICROPY_HW_CLK_PLLM (12) @@ -69,5 +70,6 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h b/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h index b84b0a8920..24cc9228b8 100644 --- a/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/PYBLITEV10/mpconfigboard.h b/ports/stm32/boards/PYBLITEV10/mpconfigboard.h index 5037073f97..60a6980aaf 100644 --- a/ports/stm32/boards/PYBLITEV10/mpconfigboard.h +++ b/ports/stm32/boards/PYBLITEV10/mpconfigboard.h @@ -7,6 +7,7 @@ #define MICROPY_HW_HAS_MMA7660 (1) #define MICROPY_HW_HAS_LCD (1) #define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_USB (1) #define MICROPY_HW_ENABLE_SERVO (1) // HSE is 12MHz @@ -76,6 +77,7 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) // MMA accelerometer config diff --git a/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h index 4ee8e72769..4e96f785ad 100644 --- a/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/PYBV10/mpconfigboard.h b/ports/stm32/boards/PYBV10/mpconfigboard.h index bb1d620f61..5d158e6b1c 100644 --- a/ports/stm32/boards/PYBV10/mpconfigboard.h +++ b/ports/stm32/boards/PYBV10/mpconfigboard.h @@ -11,6 +11,7 @@ #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) @@ -90,6 +91,7 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h index 3d92522644..4f18ac81e3 100644 --- a/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/PYBV11/mpconfigboard.h b/ports/stm32/boards/PYBV11/mpconfigboard.h index 32377513ac..71ff528487 100644 --- a/ports/stm32/boards/PYBV11/mpconfigboard.h +++ b/ports/stm32/boards/PYBV11/mpconfigboard.h @@ -11,6 +11,7 @@ #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 12MHz #define MICROPY_HW_CLK_PLLM (12) @@ -90,6 +91,7 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h index b84b0a8920..24cc9228b8 100644 --- a/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/PYBV3/mpconfigboard.h b/ports/stm32/boards/PYBV3/mpconfigboard.h index fccba7e722..d2e7dbe20a 100644 --- a/ports/stm32/boards/PYBV3/mpconfigboard.h +++ b/ports/stm32/boards/PYBV3/mpconfigboard.h @@ -10,6 +10,7 @@ #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) @@ -79,6 +80,7 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_SET) // USB VBUS detect pin +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) // MMA accelerometer config diff --git a/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h index d3df51c101..daf9b63cec 100644 --- a/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/PYBV4/mpconfigboard.h b/ports/stm32/boards/PYBV4/mpconfigboard.h index b1678512b5..c6d9ad9ac7 100644 --- a/ports/stm32/boards/PYBV4/mpconfigboard.h +++ b/ports/stm32/boards/PYBV4/mpconfigboard.h @@ -11,6 +11,7 @@ #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) @@ -87,6 +88,7 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h index d3df51c101..daf9b63cec 100644 --- a/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/STM32F411DISC/mpconfigboard.h b/ports/stm32/boards/STM32F411DISC/mpconfigboard.h index 3b3b0db53c..13172333b7 100644 --- a/ports/stm32/boards/STM32F411DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F411DISC/mpconfigboard.h @@ -4,6 +4,7 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_USB (1) #define MICROPY_HW_ENABLE_SERVO (1) // HSE is 8MHz @@ -58,5 +59,6 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h index 921cbe5fe1..8f0b663811 100644 --- a/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/STM32F429DISC/mpconfigboard.h b/ports/stm32/boards/STM32F429DISC/mpconfigboard.h index a4c46325a5..01713f7f8a 100644 --- a/ports/stm32/boards/STM32F429DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F429DISC/mpconfigboard.h @@ -6,6 +6,7 @@ #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) @@ -62,5 +63,7 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config +#define MICROPY_HW_USB_HS (1) +#define MICROPY_HW_USB_HS_IN_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_B13) #define MICROPY_HW_USB_OTG_ID_PIN (pin_B12) diff --git a/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h index 4f5962dcbd..5b5a8a3e43 100644 --- a/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h @@ -46,9 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_HS -#define USE_USB_HS_IN_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/STM32F439/mpconfigboard.h b/ports/stm32/boards/STM32F439/mpconfigboard.h index 7ead50a215..66bfcf2ecc 100644 --- a/ports/stm32/boards/STM32F439/mpconfigboard.h +++ b/ports/stm32/boards/STM32F439/mpconfigboard.h @@ -7,6 +7,7 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // SD card detect switch #if MICROPY_HW_HAS_SDCARD @@ -21,6 +22,9 @@ #define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) //divide PLL clock by this to get core clock #define MICROPY_HW_CLK_PLLQ (8) //divide core clock by this to get 48MHz +// USB config +#define MICROPY_HW_USB_FS (1) + // UART config #define MICROPY_HW_UART1_TX (pin_A9) #define MICROPY_HW_UART1_RX (pin_A10) @@ -46,7 +50,7 @@ #define MICROPY_HW_SPI1_SCK (pin_A5) #define MICROPY_HW_SPI1_MISO (pin_A6) #define MICROPY_HW_SPI1_MOSI (pin_A7) -#if defined(USE_USB_HS_IN_FS) +#if MICROPY_HW_USB_HS_IN_FS // The HS USB uses B14 & B15 for D- and D+ #else #define MICROPY_HW_SPI2_NSS (pin_B12) diff --git a/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h index d121b18c5e..5b5a8a3e43 100644 --- a/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/STM32F4DISC/mpconfigboard.h b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h index df4222c287..66ef830bf4 100644 --- a/ports/stm32/boards/STM32F4DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h @@ -7,6 +7,7 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) @@ -74,5 +75,6 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h index d3df51c101..daf9b63cec 100644 --- a/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h index 4da9dcd90e..95201501be 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h @@ -11,6 +11,7 @@ #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 25MHz // VCOClock = HSE * PLLN / PLLM = 25 MHz * 432 / 25 = 432 MHz @@ -68,5 +69,7 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) // USB config (CN13 - USB OTG FS) +#define MICROPY_HW_USB_HS (1) +#define MICROPY_HW_USB_HS_IN_FS (1) /*#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_J12)*/ #define MICROPY_HW_USB_OTG_ID_PIN (pin_J12) diff --git a/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h b/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h index ce82549026..ff968bca99 100644 --- a/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h +++ b/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h @@ -46,9 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_HS -#define USE_USB_HS_IN_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/STM32F7DISC/mpconfigboard.h b/ports/stm32/boards/STM32F7DISC/mpconfigboard.h index 1ee8e62777..9fce1deebc 100644 --- a/ports/stm32/boards/STM32F7DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F7DISC/mpconfigboard.h @@ -7,6 +7,7 @@ #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) #define MICROPY_BOARD_EARLY_INIT STM32F7DISC_board_early_init void STM32F7DISC_board_early_init(void); @@ -69,6 +70,6 @@ void STM32F7DISC_board_early_init(void); // The Hardware VBUS detect only works on pin PA9. The STM32F7 Discovery uses // PA9 for VCP_TX functionality and connects the VBUS to pin J12 (so software // only detect). So we don't define the VBUS detect pin since that requires PA9. - +#define MICROPY_HW_USB_FS (1) /*#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_J12)*/ #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h b/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h index 3fbfb43100..ff968bca99 100644 --- a/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h +++ b/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/STM32L476DISC/mpconfigboard.h b/ports/stm32/boards/STM32L476DISC/mpconfigboard.h index 87ab3d6a6c..463ec9ccfb 100644 --- a/ports/stm32/boards/STM32L476DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32L476DISC/mpconfigboard.h @@ -8,6 +8,7 @@ void STM32L476DISC_board_early_init(void); #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_USB (1) // use external SPI flash for storage #define MICROPY_HW_SPIFLASH_SIZE_BITS (128 * 1024 * 1024) @@ -57,4 +58,5 @@ void STM32L476DISC_board_early_init(void); #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config +#define MICROPY_HW_USB_FS (1) // #define MICROPY_HW_USB_OTG_ID_PIN (pin_C12) // This is not the official ID Pin which should be PA10 diff --git a/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h b/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h index 9348e06790..6bfb28118a 100644 --- a/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h +++ b/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h @@ -45,7 +45,6 @@ extern "C" { #endif -#define USE_USB_FS /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ From fa13e0d35bc6326fb87676e33a64864e47407a00 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 13 Feb 2018 22:21:46 +1100 Subject: [PATCH 296/828] stm32: Factor out flash and SPI block-device code to separate files. Prior to this patch, storage.c was a combination of code that handled either internal flash or external SPI flash and exposed one of them as a block device for the local storage. It was also exposed to the USB MSC. This patch splits out the flash and SPI code to separate files, which each provide a general block-device interface (at the C level). Then storage.c just picks one of them to use as the local storage medium. The aim of this factoring is to allow to add new block devices in the future and allow for easier configurability. --- ports/stm32/Makefile | 2 + ports/stm32/flashbdev.c | 248 +++++++++++++++++++++++++++++ ports/stm32/spibdev.c | 78 ++++++++++ ports/stm32/storage.c | 337 +++++----------------------------------- ports/stm32/storage.h | 11 ++ 5 files changed, 378 insertions(+), 298 deletions(-) create mode 100644 ports/stm32/flashbdev.c create mode 100644 ports/stm32/spibdev.c diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 55ccafe766..1ef303cd4b 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -232,6 +232,8 @@ SRC_C = \ rng.c \ rtc.c \ flash.c \ + flashbdev.c \ + spibdev.c \ storage.c \ sdcard.c \ fatfs_port.c \ diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c new file mode 100644 index 0000000000..49fe5c6964 --- /dev/null +++ b/ports/stm32/flashbdev.c @@ -0,0 +1,248 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/obj.h" +#include "systick.h" +#include "led.h" +#include "flash.h" +#include "storage.h" + +#if !defined(MICROPY_HW_SPIFLASH_SIZE_BITS) + +// Here we try to automatically configure the location and size of the flash +// pages to use for the internal storage. We also configure the location of the +// cache used for writing. + +#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) + +#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k +#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM +#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1 +#define FLASH_MEM_SEG1_NUM_BLOCKS (224) // sectors 1,2,3,4: 16k+16k+16k+64k=112k + +// enable this to get an extra 64k of storage (uses the last sector of the flash) +#if 0 +#define FLASH_MEM_SEG2_START_ADDR (0x080e0000) // sector 11 +#define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 11: 128k +#endif + +#elif defined(STM32F401xE) || defined(STM32F411xE) || defined(STM32F446xx) + +STATIC byte flash_cache_mem[0x4000] __attribute__((aligned(4))); // 16k +#define CACHE_MEM_START_ADDR (&flash_cache_mem[0]) +#define FLASH_SECTOR_SIZE_MAX (0x4000) // 16k max due to size of cache buffer +#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1 +#define FLASH_MEM_SEG1_NUM_BLOCKS (128) // sectors 1,2,3,4: 16k+16k+16k+16k(of 64k)=64k + +#elif defined(STM32F429xx) + +#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k +#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM +#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1 +#define FLASH_MEM_SEG1_NUM_BLOCKS (224) // sectors 1,2,3,4: 16k+16k+16k+64k=112k + +#elif defined(STM32F439xx) + +#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k +#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM +#define FLASH_MEM_SEG1_START_ADDR (0x08100000) // sector 12 +#define FLASH_MEM_SEG1_NUM_BLOCKS (384) // sectors 12,13,14,15,16,17: 16k+16k+16k+16k+64k+64k(of 128k)=192k +#define FLASH_MEM_SEG2_START_ADDR (0x08140000) // sector 18 +#define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 18: 64k(of 128k) + +#elif defined(STM32F746xx) || defined(STM32F767xx) || defined(STM32F769xx) + +// The STM32F746 doesn't really have CCRAM, so we use the 64K DTCM for this. + +#define CACHE_MEM_START_ADDR (0x20000000) // DTCM data RAM, 64k +#define FLASH_SECTOR_SIZE_MAX (0x08000) // 32k max +#define FLASH_MEM_SEG1_START_ADDR (0x08008000) // sector 1 +#define FLASH_MEM_SEG1_NUM_BLOCKS (192) // sectors 1,2,3: 32k+32k+32=96k + +#elif defined(STM32L475xx) || defined(STM32L476xx) + +extern uint8_t _flash_fs_start; +extern uint8_t _flash_fs_end; + +// The STM32L475/6 doesn't have CCRAM, so we use the 32K SRAM2 for this. +#define CACHE_MEM_START_ADDR (0x10000000) // SRAM2 data RAM, 32k +#define FLASH_SECTOR_SIZE_MAX (0x00800) // 2k max +#define FLASH_MEM_SEG1_START_ADDR ((long)&_flash_fs_start) +#define FLASH_MEM_SEG1_NUM_BLOCKS ((&_flash_fs_end - &_flash_fs_start) / 512) + +#else +#error "no internal flash storage support for this MCU" +#endif + +#if !defined(FLASH_MEM_SEG2_START_ADDR) +#define FLASH_MEM_SEG2_START_ADDR (0) // no second segment +#define FLASH_MEM_SEG2_NUM_BLOCKS (0) // no second segment +#endif + +#define FLASH_FLAG_DIRTY (1) +#define FLASH_FLAG_FORCE_WRITE (2) +#define FLASH_FLAG_ERASED (4) +static __IO uint8_t flash_flags = 0; +static uint32_t flash_cache_sector_id; +static uint32_t flash_cache_sector_start; +static uint32_t flash_cache_sector_size; +static uint32_t flash_tick_counter_last_write; + +void flash_bdev_init(void) { + flash_flags = 0; + flash_cache_sector_id = 0; + flash_tick_counter_last_write = 0; +} + +uint32_t flash_bdev_num_blocks(void) { + return FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS; +} + +void flash_bdev_flush(void) { + if (flash_flags & FLASH_FLAG_DIRTY) { + flash_flags |= FLASH_FLAG_FORCE_WRITE; + while (flash_flags & FLASH_FLAG_DIRTY) { + NVIC->STIR = FLASH_IRQn; + } + } +} + +static uint8_t *flash_cache_get_addr_for_write(uint32_t flash_addr) { + uint32_t flash_sector_start; + uint32_t flash_sector_size; + uint32_t flash_sector_id = flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size); + if (flash_sector_size > FLASH_SECTOR_SIZE_MAX) { + flash_sector_size = FLASH_SECTOR_SIZE_MAX; + } + if (flash_cache_sector_id != flash_sector_id) { + flash_bdev_flush(); + memcpy((void*)CACHE_MEM_START_ADDR, (const void*)flash_sector_start, flash_sector_size); + flash_cache_sector_id = flash_sector_id; + flash_cache_sector_start = flash_sector_start; + flash_cache_sector_size = flash_sector_size; + } + flash_flags |= FLASH_FLAG_DIRTY; + led_state(PYB_LED_RED, 1); // indicate a dirty cache with LED on + flash_tick_counter_last_write = HAL_GetTick(); + return (uint8_t*)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start; +} + +static uint8_t *flash_cache_get_addr_for_read(uint32_t flash_addr) { + uint32_t flash_sector_start; + uint32_t flash_sector_size; + uint32_t flash_sector_id = flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size); + if (flash_cache_sector_id == flash_sector_id) { + // in cache, copy from there + return (uint8_t*)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start; + } + // not in cache, copy straight from flash + return (uint8_t*)flash_addr; +} + +static uint32_t convert_block_to_flash_addr(uint32_t block) { + if (block < FLASH_MEM_SEG1_NUM_BLOCKS) { + return FLASH_MEM_SEG1_START_ADDR + block * FLASH_BLOCK_SIZE; + } + if (block < FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS) { + return FLASH_MEM_SEG2_START_ADDR + (block - FLASH_MEM_SEG1_NUM_BLOCKS) * FLASH_BLOCK_SIZE; + } + // can add more flash segments here if needed, following above pattern + + // bad block + return -1; +} + +void flash_bdev_irq_handler(void) { + if (!(flash_flags & FLASH_FLAG_DIRTY)) { + return; + } + + // This code uses interrupts to erase the flash + /* + if (flash_erase_state == 0) { + flash_erase_it(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4); + flash_erase_state = 1; + return; + } + + if (flash_erase_state == 1) { + // wait for erase + // TODO add timeout + #define flash_erase_done() (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY) == RESET) + if (!flash_erase_done()) { + return; + } + flash_erase_state = 2; + } + */ + + // This code erases the flash directly, waiting for it to finish + if (!(flash_flags & FLASH_FLAG_ERASED)) { + flash_erase(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4); + flash_flags |= FLASH_FLAG_ERASED; + return; + } + + // If not a forced write, wait at least 5 seconds after last write to flush + // On file close and flash unmount we get a forced write, so we can afford to wait a while + if ((flash_flags & FLASH_FLAG_FORCE_WRITE) || sys_tick_has_passed(flash_tick_counter_last_write, 5000)) { + // sync the cache RAM buffer by writing it to the flash page + flash_write(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4); + // clear the flash flags now that we have a clean cache + flash_flags = 0; + // indicate a clean cache with LED off + led_state(PYB_LED_RED, 0); + } +} + +bool flash_bdev_readblock(uint8_t *dest, uint32_t block) { + // non-MBR block, get data from flash memory, possibly via cache + uint32_t flash_addr = convert_block_to_flash_addr(block); + if (flash_addr == -1) { + // bad block number + return false; + } + uint8_t *src = flash_cache_get_addr_for_read(flash_addr); + memcpy(dest, src, FLASH_BLOCK_SIZE); + return true; +} + +bool flash_bdev_writeblock(const uint8_t *src, uint32_t block) { + // non-MBR block, copy to cache + uint32_t flash_addr = convert_block_to_flash_addr(block); + if (flash_addr == -1) { + // bad block number + return false; + } + uint8_t *dest = flash_cache_get_addr_for_write(flash_addr); + memcpy(dest, src, FLASH_BLOCK_SIZE); + return true; +} + +#endif // !defined(MICROPY_HW_SPIFLASH_SIZE_BITS) diff --git a/ports/stm32/spibdev.c b/ports/stm32/spibdev.c new file mode 100644 index 0000000000..5e5123867d --- /dev/null +++ b/ports/stm32/spibdev.c @@ -0,0 +1,78 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "storage.h" + +#if defined(MICROPY_HW_SPIFLASH_SIZE_BITS) + +#include "drivers/memory/spiflash.h" +#include "genhdr/pins.h" + +STATIC const mp_machine_soft_spi_obj_t spiflash_spi_bus = { + .base = {&mp_machine_soft_spi_type}, + .delay_half = MICROPY_PY_MACHINE_SPI_MIN_DELAY, + .polarity = 0, + .phase = 0, + .sck = &MICROPY_HW_SPIFLASH_SCK, + .mosi = &MICROPY_HW_SPIFLASH_MOSI, + .miso = &MICROPY_HW_SPIFLASH_MISO, +}; + +STATIC const mp_spiflash_t spiflash = { + .cs = &MICROPY_HW_SPIFLASH_CS, + .spi = (mp_obj_base_t*)&spiflash_spi_bus.base, +}; + +void spi_bdev_init(void) { + mp_spiflash_init((mp_spiflash_t*)&spiflash); +} + +bool spi_bdev_readblock(uint8_t *dest, uint32_t block) { + // we must disable USB irqs to prevent MSC contention with SPI flash + uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); + + mp_spiflash_read((mp_spiflash_t*)&spiflash, + block * FLASH_BLOCK_SIZE, FLASH_BLOCK_SIZE, dest); + + restore_irq_pri(basepri); + + return true; +} + +bool spi_bdev_writeblock(const uint8_t *src, uint32_t block) { + // we must disable USB irqs to prevent MSC contention with SPI flash + uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); + + int ret = mp_spiflash_write((mp_spiflash_t*)&spiflash, + block * FLASH_BLOCK_SIZE, FLASH_BLOCK_SIZE, src); + + restore_irq_pri(basepri); + + return ret == 0; +} + +#endif // defined(MICROPY_HW_SPIFLASH_SIZE_BITS) diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index 4b329c2dbb..5eab4c7022 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2018 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,191 +27,51 @@ #include #include -#include "py/obj.h" #include "py/runtime.h" -#include "lib/oofatfs/ff.h" #include "extmod/vfs_fat.h" -#include "systick.h" #include "led.h" -#include "flash.h" #include "storage.h" #include "irq.h" #if defined(MICROPY_HW_SPIFLASH_SIZE_BITS) -#define USE_INTERNAL (0) -#else -#define USE_INTERNAL (1) -#endif -#if USE_INTERNAL - -#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) - -#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k -#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM -#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1 -#define FLASH_MEM_SEG1_NUM_BLOCKS (224) // sectors 1,2,3,4: 16k+16k+16k+64k=112k - -// enable this to get an extra 64k of storage (uses the last sector of the flash) -#if 0 -#define FLASH_MEM_SEG2_START_ADDR (0x080e0000) // sector 11 -#define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 11: 128k -#endif - -#elif defined(STM32F401xE) || defined(STM32F411xE) || defined(STM32F446xx) - -STATIC byte flash_cache_mem[0x4000] __attribute__((aligned(4))); // 16k -#define CACHE_MEM_START_ADDR (&flash_cache_mem[0]) -#define FLASH_SECTOR_SIZE_MAX (0x4000) // 16k max due to size of cache buffer -#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1 -#define FLASH_MEM_SEG1_NUM_BLOCKS (128) // sectors 1,2,3,4: 16k+16k+16k+16k(of 64k)=64k - -#elif defined(STM32F429xx) - -#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k -#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM -#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1 -#define FLASH_MEM_SEG1_NUM_BLOCKS (224) // sectors 1,2,3,4: 16k+16k+16k+64k=112k - -#elif defined(STM32F439xx) - -#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k -#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM -#define FLASH_MEM_SEG1_START_ADDR (0x08100000) // sector 12 -#define FLASH_MEM_SEG1_NUM_BLOCKS (384) // sectors 12,13,14,15,16,17: 16k+16k+16k+16k+64k+64k(of 128k)=192k -#define FLASH_MEM_SEG2_START_ADDR (0x08140000) // sector 18 -#define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 18: 64k(of 128k) - -#elif defined(STM32F746xx) || defined(STM32F767xx) || defined(STM32F769xx) - -// The STM32F746 doesn't really have CCRAM, so we use the 64K DTCM for this. - -#define CACHE_MEM_START_ADDR (0x20000000) // DTCM data RAM, 64k -#define FLASH_SECTOR_SIZE_MAX (0x08000) // 32k max -#define FLASH_MEM_SEG1_START_ADDR (0x08008000) // sector 1 -#define FLASH_MEM_SEG1_NUM_BLOCKS (192) // sectors 1,2,3: 32k+32k+32=96k - -#elif defined(STM32L475xx) || defined(STM32L476xx) - -extern uint8_t _flash_fs_start; -extern uint8_t _flash_fs_end; - -// The STM32L475/6 doesn't have CCRAM, so we use the 32K SRAM2 for this. -#define CACHE_MEM_START_ADDR (0x10000000) // SRAM2 data RAM, 32k -#define FLASH_SECTOR_SIZE_MAX (0x00800) // 2k max -#define FLASH_MEM_SEG1_START_ADDR ((long)&_flash_fs_start) -#define FLASH_MEM_SEG1_NUM_BLOCKS ((&_flash_fs_end - &_flash_fs_start) / 512) +// Use external SPI flash as the storage medium +#define BDEV_NUM_BLOCKS (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) +#define BDEV_INIT spi_bdev_init +#define BDEV_READBLOCK spi_bdev_readblock +#define BDEV_WRITEBLOCK spi_bdev_writeblock #else -#error "no storage support for this MCU" -#endif -#if !defined(FLASH_MEM_SEG2_START_ADDR) -#define FLASH_MEM_SEG2_START_ADDR (0) // no second segment -#define FLASH_MEM_SEG2_NUM_BLOCKS (0) // no second segment +// Use internal flash as the storage medium +#define BDEV_NUM_BLOCKS flash_bdev_num_blocks() +#define BDEV_INIT flash_bdev_init +#define BDEV_IRQ_HANDLER flash_bdev_irq_handler +#define BDEV_FLUSH flash_bdev_flush +#define BDEV_READBLOCK flash_bdev_readblock +#define BDEV_WRITEBLOCK flash_bdev_writeblock + #endif #define FLASH_PART1_START_BLOCK (0x100) -#define FLASH_PART1_NUM_BLOCKS (FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS) -#define FLASH_FLAG_DIRTY (1) -#define FLASH_FLAG_FORCE_WRITE (2) -#define FLASH_FLAG_ERASED (4) -static bool flash_is_initialised = false; -static __IO uint8_t flash_flags = 0; -static uint32_t flash_cache_sector_id; -static uint32_t flash_cache_sector_start; -static uint32_t flash_cache_sector_size; -static uint32_t flash_tick_counter_last_write; - -static void flash_cache_flush(void) { - if (flash_flags & FLASH_FLAG_DIRTY) { - flash_flags |= FLASH_FLAG_FORCE_WRITE; - while (flash_flags & FLASH_FLAG_DIRTY) { - NVIC->STIR = FLASH_IRQn; - } - } -} - -static uint8_t *flash_cache_get_addr_for_write(uint32_t flash_addr) { - uint32_t flash_sector_start; - uint32_t flash_sector_size; - uint32_t flash_sector_id = flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size); - if (flash_sector_size > FLASH_SECTOR_SIZE_MAX) { - flash_sector_size = FLASH_SECTOR_SIZE_MAX; - } - if (flash_cache_sector_id != flash_sector_id) { - flash_cache_flush(); - memcpy((void*)CACHE_MEM_START_ADDR, (const void*)flash_sector_start, flash_sector_size); - flash_cache_sector_id = flash_sector_id; - flash_cache_sector_start = flash_sector_start; - flash_cache_sector_size = flash_sector_size; - } - flash_flags |= FLASH_FLAG_DIRTY; - led_state(PYB_LED_RED, 1); // indicate a dirty cache with LED on - flash_tick_counter_last_write = HAL_GetTick(); - return (uint8_t*)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start; -} - -static uint8_t *flash_cache_get_addr_for_read(uint32_t flash_addr) { - uint32_t flash_sector_start; - uint32_t flash_sector_size; - uint32_t flash_sector_id = flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size); - if (flash_cache_sector_id == flash_sector_id) { - // in cache, copy from there - return (uint8_t*)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start; - } - // not in cache, copy straight from flash - return (uint8_t*)flash_addr; -} - -#else - -#include "drivers/memory/spiflash.h" -#include "genhdr/pins.h" - -#define FLASH_PART1_START_BLOCK (0x100) -#define FLASH_PART1_NUM_BLOCKS (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) - -static bool flash_is_initialised = false; - -STATIC const mp_machine_soft_spi_obj_t spiflash_spi_bus = { - .base = {&mp_machine_soft_spi_type}, - .delay_half = MICROPY_PY_MACHINE_SPI_MIN_DELAY, - .polarity = 0, - .phase = 0, - .sck = &MICROPY_HW_SPIFLASH_SCK, - .mosi = &MICROPY_HW_SPIFLASH_MOSI, - .miso = &MICROPY_HW_SPIFLASH_MISO, -}; - -STATIC const mp_spiflash_t spiflash = { - .cs = &MICROPY_HW_SPIFLASH_CS, - .spi = (mp_obj_base_t*)&spiflash_spi_bus.base, -}; - -#endif +static bool storage_is_initialised = false; void storage_init(void) { - if (!flash_is_initialised) { - #if USE_INTERNAL - flash_flags = 0; - flash_cache_sector_id = 0; - flash_tick_counter_last_write = 0; - #else - mp_spiflash_init((mp_spiflash_t*)&spiflash); - #endif - flash_is_initialised = true; - } + if (!storage_is_initialised) { + storage_is_initialised = true; - #if USE_INTERNAL - // Enable the flash IRQ, which is used to also call our storage IRQ handler - // It needs to go at a higher priority than all those components that rely on - // the flash storage (eg higher than USB MSC). - HAL_NVIC_SetPriority(FLASH_IRQn, IRQ_PRI_FLASH, IRQ_SUBPRI_FLASH); - HAL_NVIC_EnableIRQ(FLASH_IRQn); - #endif + BDEV_INIT(); + + #if defined(BDEV_IRQ_HANDLER) + // Enable the flash IRQ, which is used to also call our storage IRQ handler + // It needs to go at a higher priority than all those components that rely on + // the flash storage (eg higher than USB MSC). + HAL_NVIC_SetPriority(FLASH_IRQn, IRQ_PRI_FLASH, IRQ_SUBPRI_FLASH); + HAL_NVIC_EnableIRQ(FLASH_IRQn); + #endif + } } uint32_t storage_get_block_size(void) { @@ -219,59 +79,18 @@ uint32_t storage_get_block_size(void) { } uint32_t storage_get_block_count(void) { - return FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS; + return FLASH_PART1_START_BLOCK + BDEV_NUM_BLOCKS; } void storage_irq_handler(void) { - #if USE_INTERNAL - - if (!(flash_flags & FLASH_FLAG_DIRTY)) { - return; - } - - // This code uses interrupts to erase the flash - /* - if (flash_erase_state == 0) { - flash_erase_it(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4); - flash_erase_state = 1; - return; - } - - if (flash_erase_state == 1) { - // wait for erase - // TODO add timeout - #define flash_erase_done() (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY) == RESET) - if (!flash_erase_done()) { - return; - } - flash_erase_state = 2; - } - */ - - // This code erases the flash directly, waiting for it to finish - if (!(flash_flags & FLASH_FLAG_ERASED)) { - flash_erase(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4); - flash_flags |= FLASH_FLAG_ERASED; - return; - } - - // If not a forced write, wait at least 5 seconds after last write to flush - // On file close and flash unmount we get a forced write, so we can afford to wait a while - if ((flash_flags & FLASH_FLAG_FORCE_WRITE) || sys_tick_has_passed(flash_tick_counter_last_write, 5000)) { - // sync the cache RAM buffer by writing it to the flash page - flash_write(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4); - // clear the flash flags now that we have a clean cache - flash_flags = 0; - // indicate a clean cache with LED off - led_state(PYB_LED_RED, 0); - } - + #if defined(BDEV_IRQ_HANDLER) + BDEV_IRQ_HANDLER(); #endif } void storage_flush(void) { - #if USE_INTERNAL - flash_cache_flush(); + #if defined(BDEV_FLUSH) + BDEV_FLUSH(); #endif } @@ -311,25 +130,6 @@ static void build_partition(uint8_t *buf, int boot, int type, uint32_t start_blo buf[15] = num_blocks >> 24; } -#if USE_INTERNAL - -static uint32_t convert_block_to_flash_addr(uint32_t block) { - if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS) { - // a block in partition 1 - block -= FLASH_PART1_START_BLOCK; - if (block < FLASH_MEM_SEG1_NUM_BLOCKS) { - return FLASH_MEM_SEG1_START_ADDR + block * FLASH_BLOCK_SIZE; - } else if (block < FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS) { - return FLASH_MEM_SEG2_START_ADDR + (block - FLASH_MEM_SEG1_NUM_BLOCKS) * FLASH_BLOCK_SIZE; - } - // can add more flash segments here if needed, following above pattern - } - // bad block - return -1; -} - -#endif - bool storage_read_block(uint8_t *dest, uint32_t block) { //printf("RD %u\n", block); if (block == 0) { @@ -339,7 +139,7 @@ bool storage_read_block(uint8_t *dest, uint32_t block) { dest[i] = 0; } - build_partition(dest + 446, 0, 0x01 /* FAT12 */, FLASH_PART1_START_BLOCK, FLASH_PART1_NUM_BLOCKS); + build_partition(dest + 446, 0, 0x01 /* FAT12 */, FLASH_PART1_START_BLOCK, BDEV_NUM_BLOCKS); build_partition(dest + 462, 0, 0, 0, 0); build_partition(dest + 478, 0, 0, 0, 0); build_partition(dest + 494, 0, 0, 0, 0); @@ -349,39 +149,10 @@ bool storage_read_block(uint8_t *dest, uint32_t block) { return true; + } else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + BDEV_NUM_BLOCKS) { + return BDEV_READBLOCK(dest, block - FLASH_PART1_START_BLOCK); } else { - #if USE_INTERNAL - - // non-MBR block, get data from flash memory, possibly via cache - uint32_t flash_addr = convert_block_to_flash_addr(block); - if (flash_addr == -1) { - // bad block number - return false; - } - uint8_t *src = flash_cache_get_addr_for_read(flash_addr); - memcpy(dest, src, FLASH_BLOCK_SIZE); - return true; - - #else - - // non-MBR block, get data from SPI flash - - if (block < FLASH_PART1_START_BLOCK || block >= FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS) { - // bad block number - return false; - } - - // we must disable USB irqs to prevent MSC contention with SPI flash - uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - - mp_spiflash_read((mp_spiflash_t*)&spiflash, - (block - FLASH_PART1_START_BLOCK) * FLASH_BLOCK_SIZE, FLASH_BLOCK_SIZE, dest); - - restore_irq_pri(basepri); - - return true; - - #endif + return false; } } @@ -390,40 +161,10 @@ bool storage_write_block(const uint8_t *src, uint32_t block) { if (block == 0) { // can't write MBR, but pretend we did return true; - + } else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + BDEV_NUM_BLOCKS) { + return BDEV_WRITEBLOCK(src, block - FLASH_PART1_START_BLOCK); } else { - #if USE_INTERNAL - - // non-MBR block, copy to cache - uint32_t flash_addr = convert_block_to_flash_addr(block); - if (flash_addr == -1) { - // bad block number - return false; - } - uint8_t *dest = flash_cache_get_addr_for_write(flash_addr); - memcpy(dest, src, FLASH_BLOCK_SIZE); - return true; - - #else - - // non-MBR block, write to SPI flash - - if (block < FLASH_PART1_START_BLOCK || block >= FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS) { - // bad block number - return false; - } - - // we must disable USB irqs to prevent MSC contention with SPI flash - uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - - int ret = mp_spiflash_write((mp_spiflash_t*)&spiflash, - (block - FLASH_PART1_START_BLOCK) * FLASH_BLOCK_SIZE, FLASH_BLOCK_SIZE, src); - - restore_irq_pri(basepri); - - return ret == 0; - - #endif + return false; } } diff --git a/ports/stm32/storage.h b/ports/stm32/storage.h index 291e09a9ae..5533a2a930 100644 --- a/ports/stm32/storage.h +++ b/ports/stm32/storage.h @@ -43,6 +43,17 @@ bool storage_write_block(const uint8_t *src, uint32_t block); mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks); mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks); +uint32_t flash_bdev_num_blocks(void); +void flash_bdev_init(void); +void flash_bdev_irq_handler(void); +void flash_bdev_flush(void); +bool flash_bdev_readblock(uint8_t *dest, uint32_t block); +bool flash_bdev_writeblock(const uint8_t *src, uint32_t block); + +void spi_bdev_init(void); +bool spi_bdev_readblock(uint8_t *dest, uint32_t block); +bool spi_bdev_writeblock(const uint8_t *src, uint32_t block); + extern const struct _mp_obj_type_t pyb_flash_type; struct _fs_user_mount_t; From e6235fe6470b0513000cb0206079be0b9975a122 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 14 Feb 2018 10:52:45 +1100 Subject: [PATCH 297/828] teensy: Update GPIO speed consts to align with changes in stm32 port. --- ports/teensy/hal_gpio.c | 2 +- ports/teensy/led.c | 2 +- ports/teensy/teensy_hal.h | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ports/teensy/hal_gpio.c b/ports/teensy/hal_gpio.c index e65d03410e..f9e137602c 100644 --- a/ports/teensy/hal_gpio.c +++ b/ports/teensy/hal_gpio.c @@ -52,7 +52,7 @@ void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init) *port_pcr |= PORT_PCR_DSE; /* Configure the IO Speed */ - if (GPIO_Init->Speed > GPIO_SPEED_MEDIUM) { + if (GPIO_Init->Speed > GPIO_SPEED_FREQ_MEDIUM) { *port_pcr &= ~PORT_PCR_SRE; } else { *port_pcr |= PORT_PCR_SRE; diff --git a/ports/teensy/led.c b/ports/teensy/led.c index add052fad2..cf59dbd0a3 100644 --- a/ports/teensy/led.c +++ b/ports/teensy/led.c @@ -33,7 +33,7 @@ void led_init(void) { GPIO_InitTypeDef GPIO_InitStructure; /* Configure I/O speed, mode, output type and pull */ - GPIO_InitStructure.Speed = GPIO_SPEED_LOW; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStructure.Mode = MICROPY_HW_LED_OTYPE; GPIO_InitStructure.Pull = GPIO_NOPULL; diff --git a/ports/teensy/teensy_hal.h b/ports/teensy/teensy_hal.h index 162effa85c..aef38a2ad9 100644 --- a/ports/teensy/teensy_hal.h +++ b/ports/teensy/teensy_hal.h @@ -74,10 +74,10 @@ typedef struct { #define IS_GPIO_PULL(PULL) (((PULL) == GPIO_NOPULL) || ((PULL) == GPIO_PULLUP) || \ ((PULL) == GPIO_PULLDOWN)) -#define GPIO_SPEED_LOW ((uint32_t)0) -#define GPIO_SPEED_MEDIUM ((uint32_t)1) -#define GPIO_SPEED_FAST ((uint32_t)2) -#define GPIO_SPEED_HIGH ((uint32_t)3) +#define GPIO_SPEED_FREQ_LOW ((uint32_t)0) +#define GPIO_SPEED_FREQ_MEDIUM ((uint32_t)1) +#define GPIO_SPEED_FREQ_HIGH ((uint32_t)2) +#define GPIO_SPEED_FREQ_VERY_HIGH ((uint32_t)3) #define IS_GPIO_AF(af) ((af) >= 0 && (af) <= 7) From 24c513cbc31fcc9df2ceda1666b1e1a82879a95e Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 14 Feb 2018 15:24:21 +1100 Subject: [PATCH 298/828] unix/Makefile,embedding/Makefile: Remove obsolete use of STMHAL_SRC_C. --- examples/embedding/Makefile.upylib | 1 - ports/unix/Makefile | 1 - 2 files changed, 2 deletions(-) diff --git a/examples/embedding/Makefile.upylib b/examples/embedding/Makefile.upylib index a9b6535170..469f1f76e5 100644 --- a/examples/embedding/Makefile.upylib +++ b/examples/embedding/Makefile.upylib @@ -159,7 +159,6 @@ endif OBJ = $(PY_O) OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(STMHAL_SRC_C:.c=.o)) # List of sources for qstr extraction SRC_QSTR += $(SRC_C) $(LIB_SRC_C) diff --git a/ports/unix/Makefile b/ports/unix/Makefile index f7b260e18d..cbdd3f3fbe 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -165,7 +165,6 @@ LIB_SRC_C += $(addprefix lib/,\ OBJ = $(PY_O) OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(STMHAL_SRC_C:.c=.o)) # List of sources for qstr extraction SRC_QSTR += $(SRC_C) $(LIB_SRC_C) From 6031957473a15f62ecbe59b9d27e58e9d06a4d8a Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 14 Feb 2018 16:46:44 +1100 Subject: [PATCH 299/828] tests: Automatically skip tests that require eval, exec or frozenset. --- tests/basics/builtin_eval.py | 6 ++++++ tests/basics/builtin_eval_error.py | 6 ++++++ tests/basics/builtin_exec.py | 8 ++++++++ tests/basics/fun_calldblstar2.py | 6 ++++++ tests/basics/lexer.py | 7 +++++++ tests/basics/python34.py | 6 ++++++ tests/basics/syntaxerror.py | 6 ++++++ tests/micropython/heapalloc_iter.py | 3 ++- 8 files changed, 47 insertions(+), 1 deletion(-) diff --git a/tests/basics/builtin_eval.py b/tests/basics/builtin_eval.py index 8b9d02e61b..9b49a2015f 100644 --- a/tests/basics/builtin_eval.py +++ b/tests/basics/builtin_eval.py @@ -1,5 +1,11 @@ # builtin eval +try: + eval +except NameError: + print("SKIP") + raise SystemExit + eval('1 + 2') eval('1 + 2\n') eval('1 + 2\n\n#comment\n') diff --git a/tests/basics/builtin_eval_error.py b/tests/basics/builtin_eval_error.py index 671eedab65..ef0a32da0f 100644 --- a/tests/basics/builtin_eval_error.py +++ b/tests/basics/builtin_eval_error.py @@ -1,5 +1,11 @@ # test if eval raises SyntaxError +try: + eval +except NameError: + print("SKIP") + raise SystemExit + try: print(eval("[1,,]")) except SyntaxError: diff --git a/tests/basics/builtin_exec.py b/tests/basics/builtin_exec.py index fd4e65c539..2e417a43a5 100644 --- a/tests/basics/builtin_exec.py +++ b/tests/basics/builtin_exec.py @@ -1,3 +1,11 @@ +# test builtin exec + +try: + exec +except NameError: + print("SKIP") + raise SystemExit + print(exec("def foo(): return 42")) print(foo()) diff --git a/tests/basics/fun_calldblstar2.py b/tests/basics/fun_calldblstar2.py index cf982ef5b8..8795eaf159 100644 --- a/tests/basics/fun_calldblstar2.py +++ b/tests/basics/fun_calldblstar2.py @@ -1,5 +1,11 @@ # test passing a string object as the key for a keyword argument +try: + exec +except NameError: + print("SKIP") + raise SystemExit + # they key in this dict is a string object and is not interned args = {'thisisaverylongargumentname': 123} diff --git a/tests/basics/lexer.py b/tests/basics/lexer.py index 244de8cb98..181d62db1a 100644 --- a/tests/basics/lexer.py +++ b/tests/basics/lexer.py @@ -1,5 +1,12 @@ # test the lexer +try: + eval + exec +except NameError: + print("SKIP") + raise SystemExit + # __debug__ is a special symbol print(type(__debug__)) diff --git a/tests/basics/python34.py b/tests/basics/python34.py index d5cc59ad6c..36531f11cf 100644 --- a/tests/basics/python34.py +++ b/tests/basics/python34.py @@ -1,5 +1,11 @@ # tests that differ when running under Python 3.4 vs 3.5/3.6 +try: + exec +except NameError: + print("SKIP") + raise SystemExit + # from basics/fun_kwvarargs.py # test evaluation order of arguments (in 3.4 it's backwards, 3.5 it's fixed) def f4(*vargs, **kwargs): diff --git a/tests/basics/syntaxerror.py b/tests/basics/syntaxerror.py index 843459f0bf..8e706c6e23 100644 --- a/tests/basics/syntaxerror.py +++ b/tests/basics/syntaxerror.py @@ -1,5 +1,11 @@ # test syntax errors +try: + exec +except NameError: + print("SKIP") + raise SystemExit + def test_syntax(code): try: exec(code) diff --git a/tests/micropython/heapalloc_iter.py b/tests/micropython/heapalloc_iter.py index 30ac82e14b..163e172111 100644 --- a/tests/micropython/heapalloc_iter.py +++ b/tests/micropython/heapalloc_iter.py @@ -1,7 +1,8 @@ # test that iterating doesn't use the heap try: + frozenset import array -except ImportError: +except (NameError, ImportError): print("SKIP") raise SystemExit From 04c55f582866b700c5c39158ee76a1b970b71375 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 14 Feb 2018 16:50:20 +1100 Subject: [PATCH 300/828] tests: Rewrite some tests so they can run without needing eval/exec. For builds without the compiler enabled (and hence without eval/exec) it is useful to still be able to run as many tests as possible. --- tests/basics/fun_error.py | 45 ++++++++----- tests/basics/fun_error2.py | 14 ++-- tests/basics/op_error.py | 99 +++++++++++++++++++++-------- tests/basics/op_error_intbig.py | 5 +- tests/basics/op_error_memoryview.py | 15 ++--- 5 files changed, 114 insertions(+), 64 deletions(-) diff --git a/tests/basics/fun_error.py b/tests/basics/fun_error.py index 367fe0b7fa..3e79c727b3 100644 --- a/tests/basics/fun_error.py +++ b/tests/basics/fun_error.py @@ -1,31 +1,44 @@ # test errors from bad function calls -def test_exc(code, exc): - try: - exec(code) - print("no exception") - except exc: - print("right exception") - except: - print("wrong exception") - # function doesn't take keyword args -test_exc("[].append(x=1)", TypeError) +try: + [].append(x=1) +except TypeError: + print('TypeError') # function with variable number of positional args given too few -test_exc("round()", TypeError) +try: + round() +except TypeError: + print('TypeError') # function with variable number of positional args given too many -test_exc("round(1, 2, 3)", TypeError) +try: + round(1, 2, 3) +except TypeError: + print('TypeError') # function with fixed number of positional args given wrong number -test_exc("[].append(1, 2)", TypeError) +try: + [].append(1, 2) +except TypeError: + print('TypeError') # function with keyword args given extra positional args -test_exc("[].sort(1)", TypeError) +try: + [].sort(1) +except TypeError: + print('TypeError') # function with keyword args given extra keyword args -test_exc("[].sort(noexist=1)", TypeError) +try: + [].sort(noexist=1) +except TypeError: + print('TypeError') # kw given for positional, but a different positional is missing -test_exc("def f(x, y): pass\nf(x=1)", TypeError) +try: + def f(x, y): pass + f(x=1) +except TypeError: + print('TypeError') diff --git a/tests/basics/fun_error2.py b/tests/basics/fun_error2.py index 2a00396e65..39fd0af144 100644 --- a/tests/basics/fun_error2.py +++ b/tests/basics/fun_error2.py @@ -5,14 +5,8 @@ except: print("SKIP") raise SystemExit -def test_exc(code, exc): - try: - exec(code) - print("no exception") - except exc: - print("right exception") - except: - print("wrong exception") - # function with keyword args not given a specific keyword arg -test_exc("enumerate()", TypeError) +try: + enumerate() +except TypeError: + print('TypeError') diff --git a/tests/basics/op_error.py b/tests/basics/op_error.py index b30b5f0a35..7b4f896e14 100644 --- a/tests/basics/op_error.py +++ b/tests/basics/op_error.py @@ -1,44 +1,89 @@ # test errors from bad operations (unary, binary, etc) -def test_exc(code, exc): - try: - exec(code) - print("no exception") - except exc: - print("right exception") - except: - print("wrong exception") - # unsupported unary operators -test_exc("~None", TypeError) -test_exc("~''", TypeError) -test_exc("~[]", TypeError) -test_exc("~bytearray()", TypeError) +try: + ~None +except TypeError: + print('TypeError') +try: + ~'' +except TypeError: + print('TypeError') +try: + ~[] +except TypeError: + print('TypeError') +try: + ~bytearray() +except TypeError: + print('TypeError') # unsupported binary operators -test_exc("False in True", TypeError) -test_exc("1 * {}", TypeError) -test_exc("1 in 1", TypeError) -test_exc("bytearray() // 2", TypeError) +try: + False in True +except TypeError: + print('TypeError') +try: + 1 * {} +except TypeError: + print('TypeError') +try: + 1 in 1 +except TypeError: + print('TypeError') +try: + bytearray() // 2 +except TypeError: + print('TypeError') # object with buffer protocol needed on rhs -test_exc("bytearray(1) + 1", TypeError) +try: + bytearray(1) + 1 +except TypeError: + print('TypeError') # unsupported subscription -test_exc("1[0]", TypeError) -test_exc("1[0] = 1", TypeError) -test_exc("''['']", TypeError) -test_exc("'a'[0] = 1", TypeError) -test_exc("del 1[0]", TypeError) +try: + 1[0] +except TypeError: + print('TypeError') +try: + 1[0] = 1 +except TypeError: + print('TypeError') +try: + ''[''] +except TypeError: + print('TypeError') +try: + 'a'[0] = 1 +except TypeError: + print('TypeError') +try: + del 1[0] +except TypeError: + print('TypeError') # not callable -test_exc("1()", TypeError) +try: + 1() +except TypeError: + print('TypeError') # not an iterator -test_exc("next(1)", TypeError) +try: + next(1) +except TypeError: + print('TypeError') # must be an exception type -test_exc("raise 1", TypeError) +try: + raise 1 +except TypeError: + print('TypeError') # no such name in import -test_exc("from sys import youcannotimportmebecauseidontexist", ImportError) +try: + from sys import youcannotimportmebecauseidontexist +except ImportError: + print('ImportError') diff --git a/tests/basics/op_error_intbig.py b/tests/basics/op_error_intbig.py index 432c05a9fe..7def75b0c6 100644 --- a/tests/basics/op_error_intbig.py +++ b/tests/basics/op_error_intbig.py @@ -10,4 +10,7 @@ def test_exc(code, exc): print("wrong exception") # object with buffer protocol needed on rhs -test_exc("(1 << 70) in 1", TypeError) +try: + (1 << 70) in 1 +except TypeError: + print('TypeError') diff --git a/tests/basics/op_error_memoryview.py b/tests/basics/op_error_memoryview.py index 8d4403f777..233f7f9ab7 100644 --- a/tests/basics/op_error_memoryview.py +++ b/tests/basics/op_error_memoryview.py @@ -5,14 +5,9 @@ except: print("SKIP") raise SystemExit -def test_exc(code, exc): - try: - exec(code) - print("no exception") - except exc: - print("right exception") - except: - print("wrong exception") - # unsupported binary operators -test_exc("m = memoryview(bytearray())\nm += bytearray()", TypeError) +try: + m = memoryview(bytearray()) + m += bytearray() +except TypeError: + print('TypeError') From 49e0dd54e650295fcb46b2a47ae08f369e5cfdac Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 14 Feb 2018 17:19:44 +1100 Subject: [PATCH 301/828] tests/run-tests: Capture any output from a crashed uPy execution. Instead of putting just 'CRASH' in the .py.out file, this patch makes it so any output from uPy that led to the crash is stored in the .py.out file, as well as the 'CRASH' message at the end. --- tests/run-tests | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/run-tests b/tests/run-tests index 8719befbda..627fa40dac 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -54,6 +54,7 @@ def run_micropython(pyb, args, test_file, is_special=False): 'micropython/meminfo.py', 'basics/bytes_compare3.py', 'basics/builtin_help.py', 'thread/thread_exc2.py', ) + had_crash = False if pyb is None: # run on PC if test_file.startswith(('cmdline/', 'feature_check/')) or test_file in special_tests: @@ -128,8 +129,9 @@ def run_micropython(pyb, args, test_file, is_special=False): # run the actual test try: output_mupy = subprocess.check_output(cmdlist, stderr=subprocess.STDOUT) - except subprocess.CalledProcessError: - output_mupy = b'CRASH' + except subprocess.CalledProcessError as er: + had_crash = True + output_mupy = er.output + b'CRASH' # clean up if we had an intermediate .mpy file if args.via_mpy: @@ -142,13 +144,14 @@ def run_micropython(pyb, args, test_file, is_special=False): try: output_mupy = pyb.execfile(test_file) except pyboard.PyboardError: + had_crash = True output_mupy = b'CRASH' # canonical form for all ports/platforms is to use \n for end-of-line output_mupy = output_mupy.replace(b'\r\n', b'\n') # don't try to convert the output if we should skip this test - if output_mupy in (b'SKIP\n', b'CRASH'): + if had_crash or output_mupy in (b'SKIP\n', b'CRASH'): return output_mupy if is_special or test_file in special_tests: From 19aee9438a7a8cf8539536dab5147aedb6b16bb3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 14 Feb 2018 18:19:22 +1100 Subject: [PATCH 302/828] py/unicode: Clean up utf8 funcs and provide non-utf8 inline versions. This patch provides inline versions of the utf8 helper functions for the case when unicode is disabled (MICROPY_PY_BUILTINS_STR_UNICODE set to 0). This saves code size. The unichar_charlen function is also renamed to utf8_charlen to match the other utf8 helper functions, and the signature of this function is adjusted for consistency (const char* -> const byte*, mp_uint_t -> size_t). --- py/misc.h | 8 +++++++- py/modbuiltins.c | 2 +- py/objstr.c | 2 +- py/objstrunicode.c | 2 +- py/unicode.c | 29 +++++++++++------------------ 5 files changed, 21 insertions(+), 22 deletions(-) diff --git a/py/misc.h b/py/misc.h index 5d557db6fe..a14bef7fe6 100644 --- a/py/misc.h +++ b/py/misc.h @@ -121,8 +121,15 @@ typedef uint32_t unichar; typedef uint unichar; #endif +#if MICROPY_PY_BUILTINS_STR_UNICODE unichar utf8_get_char(const byte *s); const byte *utf8_next_char(const byte *s); +size_t utf8_charlen(const byte *str, size_t len); +#else +static inline unichar utf8_get_char(const byte *s) { return *s; } +static inline const byte *utf8_next_char(const byte *s) { return s + 1; } +static inline size_t utf8_charlen(const byte *str, size_t len) { (void)str; return len; } +#endif bool unichar_isspace(unichar c); bool unichar_isalpha(unichar c); @@ -135,7 +142,6 @@ bool unichar_islower(unichar c); unichar unichar_tolower(unichar c); unichar unichar_toupper(unichar c); mp_uint_t unichar_xdigit_value(unichar c); -mp_uint_t unichar_charlen(const char *str, mp_uint_t len); #define UTF8_IS_NONASCII(ch) ((ch) & 0x80) #define UTF8_IS_CONT(ch) (((ch) & 0xC0) == 0x80) diff --git a/py/modbuiltins.c b/py/modbuiltins.c index e6f82df6f4..6b8886804b 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -346,7 +346,7 @@ STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) { const char *str = mp_obj_str_get_data(o_in, &len); #if MICROPY_PY_BUILTINS_STR_UNICODE if (MP_OBJ_IS_STR(o_in)) { - len = unichar_charlen(str, len); + len = utf8_charlen((const byte*)str, len); if (len == 1) { return mp_obj_new_int(utf8_get_char((const byte*)str)); } diff --git a/py/objstr.c b/py/objstr.c index 30153813da..ed9ab4e45b 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -1704,7 +1704,7 @@ STATIC mp_obj_t str_count(size_t n_args, const mp_obj_t *args) { // if needle_len is zero then we count each gap between characters as an occurrence if (needle_len == 0) { - return MP_OBJ_NEW_SMALL_INT(unichar_charlen((const char*)start, end - start) + 1); + return MP_OBJ_NEW_SMALL_INT(utf8_charlen(start, end - start) + 1); } // count the occurrences diff --git a/py/objstrunicode.c b/py/objstrunicode.c index a1f54b8a21..badb569d79 100644 --- a/py/objstrunicode.c +++ b/py/objstrunicode.c @@ -104,7 +104,7 @@ STATIC mp_obj_t uni_unary_op(mp_unary_op_t op, mp_obj_t self_in) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(str_len != 0); case MP_UNARY_OP_LEN: - return MP_OBJ_NEW_SMALL_INT(unichar_charlen((const char *)str_data, str_len)); + return MP_OBJ_NEW_SMALL_INT(utf8_charlen(str_data, str_len)); default: return MP_OBJ_NULL; // op not supported } diff --git a/py/unicode.c b/py/unicode.c index 140b7ba712..935dc9012e 100644 --- a/py/unicode.c +++ b/py/unicode.c @@ -67,9 +67,9 @@ STATIC const uint8_t attr[] = { AT_LO, AT_LO, AT_LO, AT_PR, AT_PR, AT_PR, AT_PR, 0 }; -// TODO: Rename to str_get_char -unichar utf8_get_char(const byte *s) { #if MICROPY_PY_BUILTINS_STR_UNICODE + +unichar utf8_get_char(const byte *s) { unichar ord = *s++; if (!UTF8_IS_NONASCII(ord)) return ord; ord &= 0x7F; @@ -80,22 +80,14 @@ unichar utf8_get_char(const byte *s) { ord = (ord << 6) | (*s++ & 0x3F); } return ord; -#else - return *s; -#endif } -// TODO: Rename to str_next_char const byte *utf8_next_char(const byte *s) { -#if MICROPY_PY_BUILTINS_STR_UNICODE ++s; while (UTF8_IS_CONT(*s)) { ++s; } return s; -#else - return s + 1; -#endif } mp_uint_t utf8_ptr_to_index(const byte *s, const byte *ptr) { @@ -109,21 +101,18 @@ mp_uint_t utf8_ptr_to_index(const byte *s, const byte *ptr) { return i; } -// TODO: Rename to str_charlen -mp_uint_t unichar_charlen(const char *str, mp_uint_t len) { -#if MICROPY_PY_BUILTINS_STR_UNICODE - mp_uint_t charlen = 0; - for (const char *top = str + len; str < top; ++str) { +size_t utf8_charlen(const byte *str, size_t len) { + size_t charlen = 0; + for (const byte *top = str + len; str < top; ++str) { if (!UTF8_IS_CONT(*str)) { ++charlen; } } return charlen; -#else - return len; -#endif } +#endif + // Be aware: These unichar_is* functions are actually ASCII-only! bool unichar_isspace(unichar c) { return c < 128 && (attr[c] & FL_SPACE) != 0; @@ -183,6 +172,8 @@ mp_uint_t unichar_xdigit_value(unichar c) { return n; } +#if MICROPY_PY_BUILTINS_STR_UNICODE + bool utf8_check(const byte *p, size_t len) { uint8_t need = 0; const byte *end = p + len; @@ -210,3 +201,5 @@ bool utf8_check(const byte *p, size_t len) { } return need == 0; // no pending fragments allowed } + +#endif From e98ff40604170eb231225a4285d9ef740b8b9501 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 14 Feb 2018 18:27:14 +1100 Subject: [PATCH 303/828] py/modbuiltins: Simplify casts from char to byte ptr in builtin ord. --- py/modbuiltins.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/py/modbuiltins.c b/py/modbuiltins.c index 6b8886804b..5461816af0 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -343,19 +343,19 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_oct_obj, mp_builtin_oct); STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) { size_t len; - const char *str = mp_obj_str_get_data(o_in, &len); + const byte *str = (const byte*)mp_obj_str_get_data(o_in, &len); #if MICROPY_PY_BUILTINS_STR_UNICODE if (MP_OBJ_IS_STR(o_in)) { - len = utf8_charlen((const byte*)str, len); + len = utf8_charlen(str, len); if (len == 1) { - return mp_obj_new_int(utf8_get_char((const byte*)str)); + return mp_obj_new_int(utf8_get_char(str)); } } else #endif { // a bytes object, or a str without unicode support (don't sign extend the char) if (len == 1) { - return MP_OBJ_NEW_SMALL_INT(((const byte*)str)[0]); + return MP_OBJ_NEW_SMALL_INT(str[0]); } } From 5604b710c2490e2a7cfd1bac6cd60fc2c8527a37 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 14 Feb 2018 18:41:17 +1100 Subject: [PATCH 304/828] py/emitglue: When assigning bytecode only pass bytecode len if needed. Most embedded targets will have this bit of the code disabled, saving a small amount of code space. --- py/emitbc.c | 2 ++ py/emitglue.c | 5 ++++- py/emitglue.h | 5 ++++- py/persistentcode.c | 6 +++++- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/py/emitbc.c b/py/emitbc.c index 5e7fa623a3..32e8330006 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -437,7 +437,9 @@ void mp_emit_bc_end_pass(emit_t *emit) { } else if (emit->pass == MP_PASS_EMIT) { mp_emit_glue_assign_bytecode(emit->scope->raw_code, emit->code_base, + #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS emit->code_info_size + emit->bytecode_size, + #endif emit->const_table, #if MICROPY_PERSISTENT_CODE_SAVE emit->ct_cur_obj, emit->ct_cur_raw_code, diff --git a/py/emitglue.c b/py/emitglue.c index d2add988f2..74bf8ddca2 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -55,7 +55,10 @@ mp_raw_code_t *mp_emit_glue_new_raw_code(void) { return rc; } -void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, mp_uint_t len, +void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, + #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS + size_t len, + #endif const mp_uint_t *const_table, #if MICROPY_PERSISTENT_CODE_SAVE uint16_t n_obj, uint16_t n_raw_code, diff --git a/py/emitglue.h b/py/emitglue.h index f2a48c5e51..0830a0d5c8 100644 --- a/py/emitglue.h +++ b/py/emitglue.h @@ -63,7 +63,10 @@ typedef struct _mp_raw_code_t { mp_raw_code_t *mp_emit_glue_new_raw_code(void); -void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, mp_uint_t len, +void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, + #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS + size_t len, + #endif const mp_uint_t *const_table, #if MICROPY_PERSISTENT_CODE_SAVE uint16_t n_obj, uint16_t n_raw_code, diff --git a/py/persistentcode.c b/py/persistentcode.c index e0bb8f1d65..7113b0dc2e 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -200,7 +200,11 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader) { // create raw_code and return it mp_raw_code_t *rc = mp_emit_glue_new_raw_code(); - mp_emit_glue_assign_bytecode(rc, bytecode, bc_len, const_table, + mp_emit_glue_assign_bytecode(rc, bytecode, + #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS + bc_len, + #endif + const_table, #if MICROPY_PERSISTENT_CODE_SAVE n_obj, n_raw_code, #endif From d77da83d55c5de4768720fa578b9ffa5ec502dc6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 14 Feb 2018 23:17:06 +1100 Subject: [PATCH 305/828] py/objrange: Implement (in)equality comparison between range objects. This feature is not often used so is guarded by the config option MICROPY_PY_BUILTINS_RANGE_BINOP which is disabled by default. With this option disabled MicroPython will always return false when comparing two range objects for equality (unless they are exactly the same object instance). This does not match CPython so if (in)equality between range objects is needed then this option should be enabled. Enabling this option costs between 100 and 200 bytes of code space depending on the machine architecture. --- py/mpconfig.h | 8 ++++++++ py/objrange.c | 21 +++++++++++++++++++ tests/basics/builtin_range_binop.py | 32 +++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 tests/basics/builtin_range_binop.py diff --git a/py/mpconfig.h b/py/mpconfig.h index f2a8c98cbb..b8a96f0b0a 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -787,6 +787,14 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_RANGE_ATTRS (1) #endif +// Whether to support binary ops [only (in)equality is defined] between range +// objects. With this option disabled all range objects that are not exactly +// the same object will compare as not-equal. With it enabled the semantics +// match CPython and ranges are equal if they yield the same sequence of items. +#ifndef MICROPY_PY_BUILTINS_RANGE_BINOP +#define MICROPY_PY_BUILTINS_RANGE_BINOP (0) +#endif + // Whether to support timeout exceptions (like socket.timeout) #ifndef MICROPY_PY_BUILTINS_TIMEOUTERROR #define MICROPY_PY_BUILTINS_TIMEOUTERROR (0) diff --git a/py/objrange.c b/py/objrange.c index 3874adb11c..86aa0ccfe6 100644 --- a/py/objrange.c +++ b/py/objrange.c @@ -138,6 +138,24 @@ STATIC mp_obj_t range_unary_op(mp_unary_op_t op, mp_obj_t self_in) { } } +#if MICROPY_PY_BUILTINS_RANGE_BINOP +STATIC mp_obj_t range_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + if (!MP_OBJ_IS_TYPE(rhs_in, &mp_type_range) || op != MP_BINARY_OP_EQUAL) { + return MP_OBJ_NULL; // op not supported + } + mp_obj_range_t *lhs = MP_OBJ_TO_PTR(lhs_in); + mp_obj_range_t *rhs = MP_OBJ_TO_PTR(rhs_in); + mp_int_t lhs_len = range_len(lhs); + mp_int_t rhs_len = range_len(rhs); + return mp_obj_new_bool( + lhs_len == rhs_len + && (lhs_len == 0 + || (lhs->start == rhs->start + && (lhs_len == 1 || lhs->step == rhs->step))) + ); +} +#endif + STATIC mp_obj_t range_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (value == MP_OBJ_SENTINEL) { // load @@ -195,6 +213,9 @@ const mp_obj_type_t mp_type_range = { .print = range_print, .make_new = range_make_new, .unary_op = range_unary_op, + #if MICROPY_PY_BUILTINS_RANGE_BINOP + .binary_op = range_binary_op, + #endif .subscr = range_subscr, .getiter = range_getiter, #if MICROPY_PY_BUILTINS_RANGE_ATTRS diff --git a/tests/basics/builtin_range_binop.py b/tests/basics/builtin_range_binop.py new file mode 100644 index 0000000000..e4e054c276 --- /dev/null +++ b/tests/basics/builtin_range_binop.py @@ -0,0 +1,32 @@ +# test binary operations on range objects; (in)equality only + +# this "feature test" actually tests the implementation but is the best we can do +if range(1) != range(1): + print("SKIP") + raise SystemExit + +# basic (in)equality +print(range(1) == range(1)) +print(range(1) != range(1)) +print(range(1) != range(2)) + +# empty range +print(range(0) == range(0)) +print(range(1, 0) == range(0)) +print(range(1, 4, -1) == range(6, 3)) + +# 1 element range +print(range(1, 4, 10) == range(1, 4, 10)) +print(range(1, 4, 10) == range(1, 4, 20)) +print(range(1, 4, 10) == range(1, 8, 20)) + +# more than 1 element +print(range(0, 3, 2) == range(0, 3, 2)) +print(range(0, 3, 2) == range(0, 4, 2)) +print(range(0, 3, 2) == range(0, 5, 2)) + +# unsupported binary op +try: + range(1) + 10 +except TypeError: + print('TypeError') From ab7819c3149326a4edd4a6ee833a2f4b733ae2d0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 14 Feb 2018 23:22:02 +1100 Subject: [PATCH 306/828] unix/mpconfigport_coverage: Enable range (in)equality comparison. --- ports/unix/mpconfigport_coverage.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/unix/mpconfigport_coverage.h b/ports/unix/mpconfigport_coverage.h index cf976bf7a3..b3fcd1e6b0 100644 --- a/ports/unix/mpconfigport_coverage.h +++ b/ports/unix/mpconfigport_coverage.h @@ -36,6 +36,7 @@ #define MICROPY_ENABLE_SCHEDULER (1) #define MICROPY_PY_DELATTR_SETATTR (1) #define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) +#define MICROPY_PY_BUILTINS_RANGE_BINOP (1) #define MICROPY_PY_BUILTINS_HELP (1) #define MICROPY_PY_BUILTINS_HELP_MODULES (1) #define MICROPY_PY_SYS_GETSIZEOF (1) From 5c83d05b493af58bb14cba9dbfc2bf2d85de2962 Mon Sep 17 00:00:00 2001 From: Olivier Ortigues Date: Mon, 12 Feb 2018 23:43:40 +0100 Subject: [PATCH 307/828] esp8266/esppwm: Clip negative duty numbers to 0. Prior to this patch a negative duty would lead to full PWM. --- ports/esp8266/esppwm.c | 4 ++-- ports/esp8266/esppwm.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ports/esp8266/esppwm.c b/ports/esp8266/esppwm.c index f1d7060dfe..f56eafc1b6 100644 --- a/ports/esp8266/esppwm.c +++ b/ports/esp8266/esppwm.c @@ -210,12 +210,12 @@ pwm_start(void) /****************************************************************************** * FunctionName : pwm_set_duty * Description : set each channel's duty params - * Parameters : uint8 duty : 0 ~ PWM_DEPTH + * Parameters : int16_t duty : 0 ~ PWM_DEPTH * uint8 channel : channel index * Returns : NONE *******************************************************************************/ void ICACHE_FLASH_ATTR -pwm_set_duty(uint16 duty, uint8 channel) +pwm_set_duty(int16_t duty, uint8 channel) { uint8 i; for(i=0;i Date: Wed, 14 Feb 2018 21:39:28 +0100 Subject: [PATCH 308/828] docs/esp8266: Update PWM doc regarding clipping of min/max values. --- docs/esp8266/tutorial/pwm.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/esp8266/tutorial/pwm.rst b/docs/esp8266/tutorial/pwm.rst index 8de509427c..61eb190f66 100644 --- a/docs/esp8266/tutorial/pwm.rst +++ b/docs/esp8266/tutorial/pwm.rst @@ -28,8 +28,8 @@ You can set the frequency and duty cycle using:: >>> pwm12.duty(512) Note that the duty cycle is between 0 (all off) and 1023 (all on), with 512 -being a 50% duty. If you print the PWM object then it will tell you its current -configuration:: +being a 50% duty. Values beyond this min/max will be clipped. If you +print the PWM object then it will tell you its current configuration:: >>> pwm12 PWM(12, freq=500, duty=512) From 359d2bdf8450ec3316eb7cc3fdc210d28cfdf91b Mon Sep 17 00:00:00 2001 From: Olivier Ortigues Date: Wed, 14 Feb 2018 21:40:16 +0100 Subject: [PATCH 309/828] esp8266/README.md: Update build instruction to reflect new ports dir. --- ports/esp8266/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp8266/README.md b/ports/esp8266/README.md index 99e2560162..f4dddd1ca1 100644 --- a/ports/esp8266/README.md +++ b/ports/esp8266/README.md @@ -49,7 +49,7 @@ $ make -C mpy-cross Then, to build MicroPython for the ESP8266, just run: ```bash -$ cd esp8266 +$ cd ports/esp8266 $ make axtls $ make ``` From 298b325f3e1385267b715af60ffcae7f71432196 Mon Sep 17 00:00:00 2001 From: Olivier Ortigues Date: Wed, 14 Feb 2018 21:41:01 +0100 Subject: [PATCH 310/828] docs/esp8266: Add a note concerning GPIO16 pull capabilities. --- docs/esp8266/tutorial/pins.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/esp8266/tutorial/pins.rst b/docs/esp8266/tutorial/pins.rst index cd45c83cd3..d304cd55b7 100644 --- a/docs/esp8266/tutorial/pins.rst +++ b/docs/esp8266/tutorial/pins.rst @@ -17,7 +17,8 @@ it. To make an input pin use:: >>> pin = machine.Pin(0, machine.Pin.IN, machine.Pin.PULL_UP) You can either use PULL_UP or None for the input pull-mode. If it's -not specified then it defaults to None, which is no pull resistor. +not specified then it defaults to None, which is no pull resistor. GPIO16 +has no pull-up mode. You can read the value on the pin using:: >>> pin.value() From 9e8b7b1b635889e365efe3e240c5fe97c0f8de0a Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Feb 2018 11:31:34 +1100 Subject: [PATCH 311/828] docs/library/ujson: Update to conform with docs conventions. The formatting of exception objects is done as per CPython conventions, eg: :exc:`TypeError` --- docs/library/ujson.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/library/ujson.rst b/docs/library/ujson.rst index 0932d0ab55..82b35ecde0 100644 --- a/docs/library/ujson.rst +++ b/docs/library/ujson.rst @@ -14,9 +14,9 @@ Functions .. function:: dumps(obj) - Return ``obj`` represented as a JSON string. + Return *obj* represented as a JSON string. .. function:: loads(str) - Parse the JSON ``str`` and return an object. Raises ValueError if the + Parse the JSON *str* and return an object. Raises :exc:`ValueError` if the string is not correctly formed. From d9bca1f7bddad762aac72b0fcbdd84eb22e1c3c1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 6 Feb 2018 15:35:52 +1100 Subject: [PATCH 312/828] extmod/modujson: Implement ujson.dump() function. --- extmod/modujson.c | 11 +++++++++++ tests/extmod/ujson_dump.py | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/extmod/ujson_dump.py diff --git a/extmod/modujson.c b/extmod/modujson.c index 6eeba4ed60..f731d71933 100644 --- a/extmod/modujson.c +++ b/extmod/modujson.c @@ -34,6 +34,16 @@ #if MICROPY_PY_UJSON +STATIC mp_obj_t mod_ujson_dump(mp_obj_t obj, mp_obj_t stream) { + if (!MP_OBJ_IS_OBJ(stream)) { + mp_raise_TypeError(NULL); + } + mp_print_t print = {MP_OBJ_TO_PTR(stream), mp_stream_write_adaptor}; + mp_obj_print_helper(&print, obj, PRINT_JSON); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ujson_dump_obj, mod_ujson_dump); + STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) { vstr_t vstr; mp_print_t print; @@ -283,6 +293,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_loads_obj, mod_ujson_loads); STATIC const mp_rom_map_elem_t mp_module_ujson_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ujson) }, + { MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&mod_ujson_dump_obj) }, { MP_ROM_QSTR(MP_QSTR_dumps), MP_ROM_PTR(&mod_ujson_dumps_obj) }, { MP_ROM_QSTR(MP_QSTR_load), MP_ROM_PTR(&mod_ujson_load_obj) }, { MP_ROM_QSTR(MP_QSTR_loads), MP_ROM_PTR(&mod_ujson_loads_obj) }, diff --git a/tests/extmod/ujson_dump.py b/tests/extmod/ujson_dump.py new file mode 100644 index 0000000000..c80e533ed7 --- /dev/null +++ b/tests/extmod/ujson_dump.py @@ -0,0 +1,18 @@ +try: + from uio import StringIO + import ujson as json +except: + try: + from io import StringIO + import json + except ImportError: + print("SKIP") + raise SystemExit + +s = StringIO() +json.dump(False, s) +print(s.getvalue()) + +s = StringIO() +json.dump({"a": (2, [3, None])}, s) +print(s.getvalue()) From e05fca4ef399b321464cae6f0ba2ddc16b58a1b2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 6 Feb 2018 15:48:24 +1100 Subject: [PATCH 313/828] docs/library/ujson: Document dump() and load() functions. --- docs/library/ujson.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/library/ujson.rst b/docs/library/ujson.rst index 82b35ecde0..5668eb21a8 100644 --- a/docs/library/ujson.rst +++ b/docs/library/ujson.rst @@ -12,10 +12,23 @@ data format. Functions --------- +.. function:: dump(obj, stream) + + Serialise *obj* to a JSON string, writing it to the given *stream*. + .. function:: dumps(obj) Return *obj* represented as a JSON string. +.. function:: load(stream) + + Parse the given *stream*, interpreting it as a JSON string and + deserialising the data to a Python object. The resulting object is + returned. + + Parsing continues until end-of-file is encountered. + A :exc:`ValueError` is raised if the data in *stream* is not correctly formed. + .. function:: loads(str) Parse the JSON *str* and return an object. Raises :exc:`ValueError` if the From d966a334869760215c19378d009800aeaaa1baec Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Feb 2018 15:47:04 +1100 Subject: [PATCH 314/828] stm32: Change header include guards from STMHAL to STM32 to match dir. --- ports/stm32/accel.h | 6 +++--- ports/stm32/adc.h | 6 +++--- ports/stm32/bufhelper.h | 6 +++--- ports/stm32/can.h | 6 +++--- ports/stm32/dac.h | 6 +++--- ports/stm32/dma.h | 6 +++--- ports/stm32/extint.h | 6 +++--- ports/stm32/flash.h | 6 +++--- ports/stm32/font_petme128_8x8.h | 6 +++--- ports/stm32/gccollect.h | 6 +++--- ports/stm32/i2c.h | 6 +++--- ports/stm32/irq.h | 6 +++--- ports/stm32/lcd.h | 6 +++--- ports/stm32/led.h | 6 +++--- ports/stm32/modmachine.h | 6 +++--- ports/stm32/modnetwork.h | 6 +++--- ports/stm32/pendsv.h | 6 +++--- ports/stm32/pin.h | 6 +++--- ports/stm32/portmodules.h | 6 +++--- ports/stm32/pybthread.h | 6 +++--- ports/stm32/rng.h | 6 +++--- ports/stm32/rtc.h | 6 +++--- ports/stm32/sdcard.h | 6 +++--- ports/stm32/servo.h | 6 +++--- ports/stm32/spi.h | 6 +++--- ports/stm32/stm32_it.h | 6 +++--- ports/stm32/storage.h | 6 +++--- ports/stm32/systick.h | 6 +++--- ports/stm32/timer.h | 6 +++--- ports/stm32/uart.h | 6 +++--- ports/stm32/usb.h | 6 +++--- ports/stm32/usbd_cdc_interface.h | 6 +++--- ports/stm32/usbd_desc.h | 6 +++--- ports/stm32/usbd_hid_interface.h | 6 +++--- ports/stm32/usbd_msc_storage.h | 6 +++--- ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h | 6 +++--- ports/stm32/usrsw.h | 6 +++--- ports/stm32/wdt.h | 6 +++--- 38 files changed, 114 insertions(+), 114 deletions(-) diff --git a/ports/stm32/accel.h b/ports/stm32/accel.h index fc35f77756..1fea1249c7 100644 --- a/ports/stm32/accel.h +++ b/ports/stm32/accel.h @@ -23,11 +23,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_ACCEL_H -#define MICROPY_INCLUDED_STMHAL_ACCEL_H +#ifndef MICROPY_INCLUDED_STM32_ACCEL_H +#define MICROPY_INCLUDED_STM32_ACCEL_H extern const mp_obj_type_t pyb_accel_type; void accel_init(void); -#endif // MICROPY_INCLUDED_STMHAL_ACCEL_H +#endif // MICROPY_INCLUDED_STM32_ACCEL_H diff --git a/ports/stm32/adc.h b/ports/stm32/adc.h index c90e6b3433..4ae6022bc3 100644 --- a/ports/stm32/adc.h +++ b/ports/stm32/adc.h @@ -23,10 +23,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_ADC_H -#define MICROPY_INCLUDED_STMHAL_ADC_H +#ifndef MICROPY_INCLUDED_STM32_ADC_H +#define MICROPY_INCLUDED_STM32_ADC_H extern const mp_obj_type_t pyb_adc_type; extern const mp_obj_type_t pyb_adc_all_type; -#endif // MICROPY_INCLUDED_STMHAL_ADC_H +#endif // MICROPY_INCLUDED_STM32_ADC_H diff --git a/ports/stm32/bufhelper.h b/ports/stm32/bufhelper.h index c1967bf430..12c79c2fda 100644 --- a/ports/stm32/bufhelper.h +++ b/ports/stm32/bufhelper.h @@ -23,10 +23,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_BUFHELPER_H -#define MICROPY_INCLUDED_STMHAL_BUFHELPER_H +#ifndef MICROPY_INCLUDED_STM32_BUFHELPER_H +#define MICROPY_INCLUDED_STM32_BUFHELPER_H void pyb_buf_get_for_send(mp_obj_t o, mp_buffer_info_t *bufinfo, byte *tmp_data); mp_obj_t pyb_buf_get_for_recv(mp_obj_t o, vstr_t *vstr); -#endif // MICROPY_INCLUDED_STMHAL_BUFHELPER_H +#endif // MICROPY_INCLUDED_STM32_BUFHELPER_H diff --git a/ports/stm32/can.h b/ports/stm32/can.h index 8600128139..b725b59249 100644 --- a/ports/stm32/can.h +++ b/ports/stm32/can.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_CAN_H -#define MICROPY_INCLUDED_STMHAL_CAN_H +#ifndef MICROPY_INCLUDED_STM32_CAN_H +#define MICROPY_INCLUDED_STM32_CAN_H #define PYB_CAN_1 (1) #define PYB_CAN_2 (2) @@ -35,4 +35,4 @@ void can_init0(void); void can_deinit(void); void can_rx_irq_handler(uint can_id, uint fifo_id); -#endif // MICROPY_INCLUDED_STMHAL_CAN_H +#endif // MICROPY_INCLUDED_STM32_CAN_H diff --git a/ports/stm32/dac.h b/ports/stm32/dac.h index f487f52a92..1d8f0ab61e 100644 --- a/ports/stm32/dac.h +++ b/ports/stm32/dac.h @@ -23,11 +23,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_DAC_H -#define MICROPY_INCLUDED_STMHAL_DAC_H +#ifndef MICROPY_INCLUDED_STM32_DAC_H +#define MICROPY_INCLUDED_STM32_DAC_H void dac_init(void); extern const mp_obj_type_t pyb_dac_type; -#endif // MICROPY_INCLUDED_STMHAL_DAC_H +#endif // MICROPY_INCLUDED_STM32_DAC_H diff --git a/ports/stm32/dma.h b/ports/stm32/dma.h index 55fb621758..0055181612 100644 --- a/ports/stm32/dma.h +++ b/ports/stm32/dma.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_DMA_H -#define MICROPY_INCLUDED_STMHAL_DMA_H +#ifndef MICROPY_INCLUDED_STM32_DMA_H +#define MICROPY_INCLUDED_STM32_DMA_H typedef struct _dma_descr_t dma_descr_t; @@ -100,4 +100,4 @@ void dma_deinit(const dma_descr_t *dma_descr); void dma_invalidate_channel(const dma_descr_t *dma_descr); void dma_idle_handler(int controller); -#endif // MICROPY_INCLUDED_STMHAL_DMA_H +#endif // MICROPY_INCLUDED_STM32_DMA_H diff --git a/ports/stm32/extint.h b/ports/stm32/extint.h index 846790b9be..0bd20affa7 100644 --- a/ports/stm32/extint.h +++ b/ports/stm32/extint.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_EXTINT_H -#define MICROPY_INCLUDED_STMHAL_EXTINT_H +#ifndef MICROPY_INCLUDED_STM32_EXTINT_H +#define MICROPY_INCLUDED_STM32_EXTINT_H // Vectors 0-15 are for regular pins // Vectors 16-22 are for internal sources. @@ -64,4 +64,4 @@ void Handle_EXTI_Irq(uint32_t line); extern const mp_obj_type_t extint_type; -#endif // MICROPY_INCLUDED_STMHAL_EXTINT_H +#endif // MICROPY_INCLUDED_STM32_EXTINT_H diff --git a/ports/stm32/flash.h b/ports/stm32/flash.h index 688e70a3cd..d69f6e27f6 100644 --- a/ports/stm32/flash.h +++ b/ports/stm32/flash.h @@ -23,11 +23,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_FLASH_H -#define MICROPY_INCLUDED_STMHAL_FLASH_H +#ifndef MICROPY_INCLUDED_STM32_FLASH_H +#define MICROPY_INCLUDED_STM32_FLASH_H uint32_t flash_get_sector_info(uint32_t addr, uint32_t *start_addr, uint32_t *size); void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32); void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32); -#endif // MICROPY_INCLUDED_STMHAL_FLASH_H +#endif // MICROPY_INCLUDED_STM32_FLASH_H diff --git a/ports/stm32/font_petme128_8x8.h b/ports/stm32/font_petme128_8x8.h index 8b0cc9cb01..cdc4e73a79 100644 --- a/ports/stm32/font_petme128_8x8.h +++ b/ports/stm32/font_petme128_8x8.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_FONT_PETME128_8X8_H -#define MICROPY_INCLUDED_STMHAL_FONT_PETME128_8X8_H +#ifndef MICROPY_INCLUDED_STM32_FONT_PETME128_8X8_H +#define MICROPY_INCLUDED_STM32_FONT_PETME128_8X8_H static const uint8_t font_petme128_8x8[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 32= @@ -125,4 +125,4 @@ static const uint8_t font_petme128_8x8[] = { 0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55, // 127 }; -#endif // MICROPY_INCLUDED_STMHAL_FONT_PETME128_8X8_H +#endif // MICROPY_INCLUDED_STM32_FONT_PETME128_8X8_H diff --git a/ports/stm32/gccollect.h b/ports/stm32/gccollect.h index 1b64a51a6a..25a74a306a 100644 --- a/ports/stm32/gccollect.h +++ b/ports/stm32/gccollect.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_GCCOLLECT_H -#define MICROPY_INCLUDED_STMHAL_GCCOLLECT_H +#ifndef MICROPY_INCLUDED_STM32_GCCOLLECT_H +#define MICROPY_INCLUDED_STM32_GCCOLLECT_H // variables defining memory layout // (these probably belong somewhere else...) @@ -40,4 +40,4 @@ extern uint32_t _heap_end; extern uint32_t _estack; extern uint32_t _ram_end; -#endif // MICROPY_INCLUDED_STMHAL_GCCOLLECT_H +#endif // MICROPY_INCLUDED_STM32_GCCOLLECT_H diff --git a/ports/stm32/i2c.h b/ports/stm32/i2c.h index 6affe3973b..f416c791ee 100644 --- a/ports/stm32/i2c.h +++ b/ports/stm32/i2c.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_I2C_H -#define MICROPY_INCLUDED_STMHAL_I2C_H +#ifndef MICROPY_INCLUDED_STM32_I2C_H +#define MICROPY_INCLUDED_STM32_I2C_H #include "dma.h" @@ -52,4 +52,4 @@ uint32_t i2c_get_baudrate(I2C_InitTypeDef *init); void i2c_ev_irq_handler(mp_uint_t i2c_id); void i2c_er_irq_handler(mp_uint_t i2c_id); -#endif // MICROPY_INCLUDED_STMHAL_I2C_H +#endif // MICROPY_INCLUDED_STM32_I2C_H diff --git a/ports/stm32/irq.h b/ports/stm32/irq.h index 2cf58639ea..d0bb49c525 100644 --- a/ports/stm32/irq.h +++ b/ports/stm32/irq.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_IRQ_H -#define MICROPY_INCLUDED_STMHAL_IRQ_H +#ifndef MICROPY_INCLUDED_STM32_IRQ_H +#define MICROPY_INCLUDED_STM32_IRQ_H // these states correspond to values from query_irq, enable_irq and disable_irq #define IRQ_STATE_DISABLED (0x00000001) @@ -149,4 +149,4 @@ MP_DECLARE_CONST_FUN_OBJ_0(pyb_irq_stats_obj); #define IRQ_PRI_RTC_WKUP 15 #define IRQ_SUBPRI_RTC_WKUP 0 -#endif // MICROPY_INCLUDED_STMHAL_IRQ_H +#endif // MICROPY_INCLUDED_STM32_IRQ_H diff --git a/ports/stm32/lcd.h b/ports/stm32/lcd.h index c0d9bd97da..98f904848f 100644 --- a/ports/stm32/lcd.h +++ b/ports/stm32/lcd.h @@ -23,9 +23,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_LCD_H -#define MICROPY_INCLUDED_STMHAL_LCD_H +#ifndef MICROPY_INCLUDED_STM32_LCD_H +#define MICROPY_INCLUDED_STM32_LCD_H extern const mp_obj_type_t pyb_lcd_type; -#endif // MICROPY_INCLUDED_STMHAL_LCD_H +#endif // MICROPY_INCLUDED_STM32_LCD_H diff --git a/ports/stm32/led.h b/ports/stm32/led.h index 2c872e9c5f..1cc96b75ab 100644 --- a/ports/stm32/led.h +++ b/ports/stm32/led.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_LED_H -#define MICROPY_INCLUDED_STMHAL_LED_H +#ifndef MICROPY_INCLUDED_STM32_LED_H +#define MICROPY_INCLUDED_STM32_LED_H typedef enum { PYB_LED_RED = 1, @@ -40,4 +40,4 @@ void led_debug(int value, int delay); extern const mp_obj_type_t pyb_led_type; -#endif // MICROPY_INCLUDED_STMHAL_LED_H +#endif // MICROPY_INCLUDED_STM32_LED_H diff --git a/ports/stm32/modmachine.h b/ports/stm32/modmachine.h index 81c6375c7e..88fe236921 100644 --- a/ports/stm32/modmachine.h +++ b/ports/stm32/modmachine.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_MODMACHINE_H -#define MICROPY_INCLUDED_STMHAL_MODMACHINE_H +#ifndef MICROPY_INCLUDED_STM32_MODMACHINE_H +#define MICROPY_INCLUDED_STM32_MODMACHINE_H #include "py/obj.h" @@ -39,4 +39,4 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj); MP_DECLARE_CONST_FUN_OBJ_0(machine_sleep_obj); MP_DECLARE_CONST_FUN_OBJ_0(machine_deepsleep_obj); -#endif // MICROPY_INCLUDED_STMHAL_MODMACHINE_H +#endif // MICROPY_INCLUDED_STM32_MODMACHINE_H diff --git a/ports/stm32/modnetwork.h b/ports/stm32/modnetwork.h index ecda94da41..6796b087a4 100644 --- a/ports/stm32/modnetwork.h +++ b/ports/stm32/modnetwork.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_MODNETWORK_H -#define MICROPY_INCLUDED_STMHAL_MODNETWORK_H +#ifndef MICROPY_INCLUDED_STM32_MODNETWORK_H +#define MICROPY_INCLUDED_STM32_MODNETWORK_H #define MOD_NETWORK_IPADDR_BUF_SIZE (4) @@ -80,4 +80,4 @@ void mod_network_init(void); void mod_network_register_nic(mp_obj_t nic); mp_obj_t mod_network_find_nic(const uint8_t *ip); -#endif // MICROPY_INCLUDED_STMHAL_MODNETWORK_H +#endif // MICROPY_INCLUDED_STM32_MODNETWORK_H diff --git a/ports/stm32/pendsv.h b/ports/stm32/pendsv.h index 6a9eb0d794..0d9fde6878 100644 --- a/ports/stm32/pendsv.h +++ b/ports/stm32/pendsv.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_PENDSV_H -#define MICROPY_INCLUDED_STMHAL_PENDSV_H +#ifndef MICROPY_INCLUDED_STM32_PENDSV_H +#define MICROPY_INCLUDED_STM32_PENDSV_H void pendsv_init(void); void pendsv_kbd_intr(void); @@ -33,4 +33,4 @@ void pendsv_kbd_intr(void); // prelude for this function void pendsv_isr_handler(void) __attribute__((naked)); -#endif // MICROPY_INCLUDED_STMHAL_PENDSV_H +#endif // MICROPY_INCLUDED_STM32_PENDSV_H diff --git a/ports/stm32/pin.h b/ports/stm32/pin.h index 90de79e5ce..2439ebbbef 100644 --- a/ports/stm32/pin.h +++ b/ports/stm32/pin.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_PIN_H -#define MICROPY_INCLUDED_STMHAL_PIN_H +#ifndef MICROPY_INCLUDED_STM32_PIN_H +#define MICROPY_INCLUDED_STM32_PIN_H // This file requires pin_defs_xxx.h (which has port specific enums and // defines, so we include it here. It should never be included directly @@ -97,4 +97,4 @@ const pin_af_obj_t *pin_find_af(const pin_obj_t *pin, uint8_t fn, uint8_t unit); const pin_af_obj_t *pin_find_af_by_index(const pin_obj_t *pin, mp_uint_t af_idx); const pin_af_obj_t *pin_find_af_by_name(const pin_obj_t *pin, const char *name); -#endif // MICROPY_INCLUDED_STMHAL_PIN_H +#endif // MICROPY_INCLUDED_STM32_PIN_H diff --git a/ports/stm32/portmodules.h b/ports/stm32/portmodules.h index b575109b89..81cb7fd04a 100644 --- a/ports/stm32/portmodules.h +++ b/ports/stm32/portmodules.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_PORTMODULES_H -#define MICROPY_INCLUDED_STMHAL_PORTMODULES_H +#ifndef MICROPY_INCLUDED_STM32_PORTMODULES_H +#define MICROPY_INCLUDED_STM32_PORTMODULES_H extern const mp_obj_module_t pyb_module; extern const mp_obj_module_t stm_module; @@ -40,4 +40,4 @@ MP_DECLARE_CONST_FUN_OBJ_1(time_sleep_us_obj); MP_DECLARE_CONST_FUN_OBJ_0(mod_os_sync_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_dupterm_obj); -#endif // MICROPY_INCLUDED_STMHAL_PORTMODULES_H +#endif // MICROPY_INCLUDED_STM32_PORTMODULES_H diff --git a/ports/stm32/pybthread.h b/ports/stm32/pybthread.h index f628f934bc..42300508c9 100644 --- a/ports/stm32/pybthread.h +++ b/ports/stm32/pybthread.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_PYBTHREAD_H -#define MICROPY_INCLUDED_STMHAL_PYBTHREAD_H +#ifndef MICROPY_INCLUDED_STM32_PYBTHREAD_H +#define MICROPY_INCLUDED_STM32_PYBTHREAD_H typedef struct _pyb_thread_t { void *sp; @@ -74,4 +74,4 @@ void pyb_mutex_init(pyb_mutex_t *m); int pyb_mutex_lock(pyb_mutex_t *m, int wait); void pyb_mutex_unlock(pyb_mutex_t *m); -#endif // MICROPY_INCLUDED_STMHAL_PYBTHREAD_H +#endif // MICROPY_INCLUDED_STM32_PYBTHREAD_H diff --git a/ports/stm32/rng.h b/ports/stm32/rng.h index 1478b7d3f2..ed9cc80f2b 100644 --- a/ports/stm32/rng.h +++ b/ports/stm32/rng.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_RNG_H -#define MICROPY_INCLUDED_STMHAL_RNG_H +#ifndef MICROPY_INCLUDED_STM32_RNG_H +#define MICROPY_INCLUDED_STM32_RNG_H #include "py/obj.h" @@ -32,4 +32,4 @@ uint32_t rng_get(void); MP_DECLARE_CONST_FUN_OBJ_0(pyb_rng_get_obj); -#endif // MICROPY_INCLUDED_STMHAL_RNG_H +#endif // MICROPY_INCLUDED_STM32_RNG_H diff --git a/ports/stm32/rtc.h b/ports/stm32/rtc.h index 09ab2aedff..307f8885e3 100644 --- a/ports/stm32/rtc.h +++ b/ports/stm32/rtc.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_RTC_H -#define MICROPY_INCLUDED_STMHAL_RTC_H +#ifndef MICROPY_INCLUDED_STM32_RTC_H +#define MICROPY_INCLUDED_STM32_RTC_H extern RTC_HandleTypeDef RTCHandle; extern const mp_obj_type_t pyb_rtc_type; @@ -32,4 +32,4 @@ extern const mp_obj_type_t pyb_rtc_type; void rtc_init_start(bool force_init); void rtc_init_finalise(void); -#endif // MICROPY_INCLUDED_STMHAL_RTC_H +#endif // MICROPY_INCLUDED_STM32_RTC_H diff --git a/ports/stm32/sdcard.h b/ports/stm32/sdcard.h index 8c698fc2f7..4afc258aa1 100644 --- a/ports/stm32/sdcard.h +++ b/ports/stm32/sdcard.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_SDCARD_H -#define MICROPY_INCLUDED_STMHAL_SDCARD_H +#ifndef MICROPY_INCLUDED_STM32_SDCARD_H +#define MICROPY_INCLUDED_STM32_SDCARD_H // this is a fixed size and should not be changed #define SDCARD_BLOCK_SIZE (512) @@ -45,4 +45,4 @@ extern const struct _mp_obj_base_t pyb_sdcard_obj; struct _fs_user_mount_t; void sdcard_init_vfs(struct _fs_user_mount_t *vfs, int part); -#endif // MICROPY_INCLUDED_STMHAL_SDCARD_H +#endif // MICROPY_INCLUDED_STM32_SDCARD_H diff --git a/ports/stm32/servo.h b/ports/stm32/servo.h index c602a07da5..0160568af1 100644 --- a/ports/stm32/servo.h +++ b/ports/stm32/servo.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_SERVO_H -#define MICROPY_INCLUDED_STMHAL_SERVO_H +#ifndef MICROPY_INCLUDED_STM32_SERVO_H +#define MICROPY_INCLUDED_STM32_SERVO_H void servo_init(void); void servo_timer_irq_callback(void); @@ -34,4 +34,4 @@ extern const mp_obj_type_t pyb_servo_type; MP_DECLARE_CONST_FUN_OBJ_2(pyb_servo_set_obj); MP_DECLARE_CONST_FUN_OBJ_2(pyb_pwm_set_obj); -#endif // MICROPY_INCLUDED_STMHAL_SERVO_H +#endif // MICROPY_INCLUDED_STM32_SERVO_H diff --git a/ports/stm32/spi.h b/ports/stm32/spi.h index fb05703bca..41f91b2896 100644 --- a/ports/stm32/spi.h +++ b/ports/stm32/spi.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_SPI_H -#define MICROPY_INCLUDED_STMHAL_SPI_H +#ifndef MICROPY_INCLUDED_STM32_SPI_H +#define MICROPY_INCLUDED_STM32_SPI_H #include "dma.h" @@ -51,4 +51,4 @@ void spi_init0(void); void spi_init(const spi_t *spi, bool enable_nss_pin); const spi_t *spi_from_mp_obj(mp_obj_t o); -#endif // MICROPY_INCLUDED_STMHAL_SPI_H +#endif // MICROPY_INCLUDED_STM32_SPI_H diff --git a/ports/stm32/stm32_it.h b/ports/stm32/stm32_it.h index 0f200fb6fe..46523e5673 100644 --- a/ports/stm32/stm32_it.h +++ b/ports/stm32/stm32_it.h @@ -25,8 +25,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_STM32_IT_H -#define MICROPY_INCLUDED_STMHAL_STM32_IT_H +#ifndef MICROPY_INCLUDED_STM32_STM32_IT_H +#define MICROPY_INCLUDED_STM32_STM32_IT_H /** ****************************************************************************** @@ -79,4 +79,4 @@ void SysTick_Handler(void); void OTG_FS_IRQHandler(void); void OTG_HS_IRQHandler(void); -#endif // MICROPY_INCLUDED_STMHAL_STM32_IT_H +#endif // MICROPY_INCLUDED_STM32_STM32_IT_H diff --git a/ports/stm32/storage.h b/ports/stm32/storage.h index 5533a2a930..37cacc1a68 100644 --- a/ports/stm32/storage.h +++ b/ports/stm32/storage.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_STORAGE_H -#define MICROPY_INCLUDED_STMHAL_STORAGE_H +#ifndef MICROPY_INCLUDED_STM32_STORAGE_H +#define MICROPY_INCLUDED_STM32_STORAGE_H #define FLASH_BLOCK_SIZE (512) @@ -59,4 +59,4 @@ extern const struct _mp_obj_type_t pyb_flash_type; struct _fs_user_mount_t; void pyb_flash_init_vfs(struct _fs_user_mount_t *vfs); -#endif // MICROPY_INCLUDED_STMHAL_STORAGE_H +#endif // MICROPY_INCLUDED_STM32_STORAGE_H diff --git a/ports/stm32/systick.h b/ports/stm32/systick.h index c1def50c29..256a500c27 100644 --- a/ports/stm32/systick.h +++ b/ports/stm32/systick.h @@ -23,10 +23,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_SYSTICK_H -#define MICROPY_INCLUDED_STMHAL_SYSTICK_H +#ifndef MICROPY_INCLUDED_STM32_SYSTICK_H +#define MICROPY_INCLUDED_STM32_SYSTICK_H void sys_tick_wait_at_least(uint32_t stc, uint32_t delay_ms); bool sys_tick_has_passed(uint32_t stc, uint32_t delay_ms); -#endif // MICROPY_INCLUDED_STMHAL_SYSTICK_H +#endif // MICROPY_INCLUDED_STM32_SYSTICK_H diff --git a/ports/stm32/timer.h b/ports/stm32/timer.h index 775accc3d4..2ba91cf158 100644 --- a/ports/stm32/timer.h +++ b/ports/stm32/timer.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_TIMER_H -#define MICROPY_INCLUDED_STMHAL_TIMER_H +#ifndef MICROPY_INCLUDED_STM32_TIMER_H +#define MICROPY_INCLUDED_STM32_TIMER_H extern TIM_HandleTypeDef TIM5_Handle; @@ -39,4 +39,4 @@ void timer_irq_handler(uint tim_id); TIM_HandleTypeDef *pyb_timer_get_handle(mp_obj_t timer); -#endif // MICROPY_INCLUDED_STMHAL_TIMER_H +#endif // MICROPY_INCLUDED_STM32_TIMER_H diff --git a/ports/stm32/uart.h b/ports/stm32/uart.h index d176520a1b..d06508e8ed 100644 --- a/ports/stm32/uart.h +++ b/ports/stm32/uart.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_UART_H -#define MICROPY_INCLUDED_STMHAL_UART_H +#ifndef MICROPY_INCLUDED_STM32_UART_H +#define MICROPY_INCLUDED_STM32_UART_H typedef enum { PYB_UART_NONE = 0, @@ -49,4 +49,4 @@ mp_uint_t uart_rx_any(pyb_uart_obj_t *uart_obj); int uart_rx_char(pyb_uart_obj_t *uart_obj); void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len); -#endif // MICROPY_INCLUDED_STMHAL_UART_H +#endif // MICROPY_INCLUDED_STM32_UART_H diff --git a/ports/stm32/usb.h b/ports/stm32/usb.h index c75d59e477..6b43af00fa 100644 --- a/ports/stm32/usb.h +++ b/ports/stm32/usb.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_USB_H -#define MICROPY_INCLUDED_STMHAL_USB_H +#ifndef MICROPY_INCLUDED_STM32_USB_H +#define MICROPY_INCLUDED_STM32_USB_H #include "usbd_cdc_msc_hid0.h" @@ -69,4 +69,4 @@ void pyb_usb_host_init(void); void pyb_usb_host_process(void); uint pyb_usb_host_get_keyboard(void); -#endif // MICROPY_INCLUDED_STMHAL_USB_H +#endif // MICROPY_INCLUDED_STM32_USB_H diff --git a/ports/stm32/usbd_cdc_interface.h b/ports/stm32/usbd_cdc_interface.h index 44926085a8..36a89e7dbc 100644 --- a/ports/stm32/usbd_cdc_interface.h +++ b/ports/stm32/usbd_cdc_interface.h @@ -1,8 +1,8 @@ /* * This file is part of the MicroPython project, http://micropython.org/ */ -#ifndef MICROPY_INCLUDED_STMHAL_USBD_CDC_INTERFACE_H -#define MICROPY_INCLUDED_STMHAL_USBD_CDC_INTERFACE_H +#ifndef MICROPY_INCLUDED_STM32_USBD_CDC_INTERFACE_H +#define MICROPY_INCLUDED_STM32_USBD_CDC_INTERFACE_H /** ****************************************************************************** @@ -63,4 +63,4 @@ void usbd_cdc_tx_always(usbd_cdc_itf_t *cdc, const uint8_t *buf, uint32_t len); int usbd_cdc_rx_num(usbd_cdc_itf_t *cdc); int usbd_cdc_rx(usbd_cdc_itf_t *cdc, uint8_t *buf, uint32_t len, uint32_t timeout); -#endif // MICROPY_INCLUDED_STMHAL_USBD_CDC_INTERFACE_H +#endif // MICROPY_INCLUDED_STM32_USBD_CDC_INTERFACE_H diff --git a/ports/stm32/usbd_desc.h b/ports/stm32/usbd_desc.h index a4de6c6819..0307defa5b 100644 --- a/ports/stm32/usbd_desc.h +++ b/ports/stm32/usbd_desc.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_USBD_DESC_H -#define MICROPY_INCLUDED_STMHAL_USBD_DESC_H +#ifndef MICROPY_INCLUDED_STM32_USBD_DESC_H +#define MICROPY_INCLUDED_STM32_USBD_DESC_H #include "usbd_cdc_msc_hid.h" @@ -32,4 +32,4 @@ extern const USBD_DescriptorsTypeDef USBD_Descriptors; void USBD_SetVIDPIDRelease(usbd_cdc_msc_hid_state_t *usbd, uint16_t vid, uint16_t pid, uint16_t device_release_num, int cdc_only); -#endif // MICROPY_INCLUDED_STMHAL_USBD_DESC_H +#endif // MICROPY_INCLUDED_STM32_USBD_DESC_H diff --git a/ports/stm32/usbd_hid_interface.h b/ports/stm32/usbd_hid_interface.h index 79040b57e9..d9adf8a5f3 100644 --- a/ports/stm32/usbd_hid_interface.h +++ b/ports/stm32/usbd_hid_interface.h @@ -1,8 +1,8 @@ /* * This file is part of the MicroPython project, http://micropython.org/ */ -#ifndef MICROPY_INCLUDED_STMHAL_USBD_HID_INTERFACE_H -#define MICROPY_INCLUDED_STMHAL_USBD_HID_INTERFACE_H +#ifndef MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_H +#define MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_H #include "usbd_cdc_msc_hid.h" @@ -18,4 +18,4 @@ typedef struct _usbd_hid_itf_t { int usbd_hid_rx_num(usbd_hid_itf_t *hid); int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout); -#endif // MICROPY_INCLUDED_STMHAL_USBD_HID_INTERFACE_H +#endif // MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_H diff --git a/ports/stm32/usbd_msc_storage.h b/ports/stm32/usbd_msc_storage.h index 6cc40d2d62..669f7df581 100644 --- a/ports/stm32/usbd_msc_storage.h +++ b/ports/stm32/usbd_msc_storage.h @@ -23,10 +23,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_USBD_MSC_STORAGE_H -#define MICROPY_INCLUDED_STMHAL_USBD_MSC_STORAGE_H +#ifndef MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H +#define MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H extern const USBD_StorageTypeDef USBD_FLASH_STORAGE_fops; extern const USBD_StorageTypeDef USBD_SDCARD_STORAGE_fops; -#endif // MICROPY_INCLUDED_STMHAL_USBD_MSC_STORAGE_H +#endif // MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h index 3bf7bccfdd..95fc693a00 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H -#define MICROPY_INCLUDED_STMHAL_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H +#ifndef MICROPY_INCLUDED_STM32_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H +#define MICROPY_INCLUDED_STM32_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H // these are exports for the CDC/MSC/HID interface that are independent // from any other definitions/declarations @@ -49,4 +49,4 @@ typedef struct _USBD_HID_ModeInfoTypeDef { const uint8_t *report_desc; } USBD_HID_ModeInfoTypeDef; -#endif // MICROPY_INCLUDED_STMHAL_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H +#endif // MICROPY_INCLUDED_STM32_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H diff --git a/ports/stm32/usrsw.h b/ports/stm32/usrsw.h index d96e3c2813..a8a087db2f 100644 --- a/ports/stm32/usrsw.h +++ b/ports/stm32/usrsw.h @@ -23,12 +23,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_USRSW_H -#define MICROPY_INCLUDED_STMHAL_USRSW_H +#ifndef MICROPY_INCLUDED_STM32_USRSW_H +#define MICROPY_INCLUDED_STM32_USRSW_H void switch_init0(void); int switch_get(void); extern const mp_obj_type_t pyb_switch_type; -#endif // MICROPY_INCLUDED_STMHAL_USRSW_H +#endif // MICROPY_INCLUDED_STM32_USRSW_H diff --git a/ports/stm32/wdt.h b/ports/stm32/wdt.h index 0a486f704d..d60bb7e9e6 100644 --- a/ports/stm32/wdt.h +++ b/ports/stm32/wdt.h @@ -23,9 +23,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_WDT_H -#define MICROPY_INCLUDED_STMHAL_WDT_H +#ifndef MICROPY_INCLUDED_STM32_WDT_H +#define MICROPY_INCLUDED_STM32_WDT_H extern const mp_obj_type_t pyb_wdt_type; -#endif // MICROPY_INCLUDED_STMHAL_WDT_H +#endif // MICROPY_INCLUDED_STM32_WDT_H From 73d1d20b46dda54340ad2819b865f47ca25f4850 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Feb 2018 16:50:02 +1100 Subject: [PATCH 315/828] py/objexcept: Remove long-obsolete mp_const_MemoryError_obj. This constant exception instance was once used by m_malloc_fail() to raise a MemoryError without allocating memory, but it was made obsolete long ago by 3556e45711c3b7ec712748d013e678d035185bdd. The functionality is now replaced by the use of mp_emergency_exception_obj which lives in the global uPy state, and which can handle any exception type, not just MemoryError. --- py/obj.h | 1 - py/objexcept.c | 3 --- py/vm.c | 3 +-- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/py/obj.h b/py/obj.h index 10cb48961f..2e715253c5 100644 --- a/py/obj.h +++ b/py/obj.h @@ -624,7 +624,6 @@ extern const struct _mp_obj_str_t mp_const_empty_bytes_obj; extern const struct _mp_obj_tuple_t mp_const_empty_tuple_obj; extern const struct _mp_obj_singleton_t mp_const_ellipsis_obj; extern const struct _mp_obj_singleton_t mp_const_notimplemented_obj; -extern const struct _mp_obj_exception_t mp_const_MemoryError_obj; extern const struct _mp_obj_exception_t mp_const_GeneratorExit_obj; // General API for objects diff --git a/py/objexcept.c b/py/objexcept.c index 524f105ce1..ccb0bad0dd 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -43,9 +43,6 @@ // Number of traceback entries to reserve in the emergency exception buffer #define EMG_TRACEBACK_ALLOC (2 * TRACEBACK_ENTRY_LEN) -// Instance of MemoryError exception - needed by mp_malloc_fail -const mp_obj_exception_t mp_const_MemoryError_obj = {{&mp_type_MemoryError}, 0, 0, NULL, (mp_obj_tuple_t*)&mp_const_empty_tuple_obj}; - // Optionally allocated buffer for storing the first argument of an exception // allocated when the heap is locked. #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF diff --git a/py/vm.c b/py/vm.c index c629a61e2f..ceb2060f9d 100644 --- a/py/vm.c +++ b/py/vm.c @@ -1374,8 +1374,7 @@ unwind_loop: // set file and line number that the exception occurred at // TODO: don't set traceback for exceptions re-raised by END_FINALLY. // But consider how to handle nested exceptions. - // TODO need a better way of not adding traceback to constant objects (right now, just GeneratorExit_obj and MemoryError_obj) - if (nlr.ret_val != &mp_const_GeneratorExit_obj && nlr.ret_val != &mp_const_MemoryError_obj) { + if (nlr.ret_val != &mp_const_GeneratorExit_obj) { const byte *ip = code_state->fun_bc->bytecode; ip = mp_decode_uint_skip(ip); // skip n_state ip = mp_decode_uint_skip(ip); // skip n_exc_stack From 44033a1d27432a700ca3bdccd5a5d81bb66599ec Mon Sep 17 00:00:00 2001 From: Eric Poulsen Date: Thu, 15 Feb 2018 07:35:37 -0800 Subject: [PATCH 316/828] esp32/machine_rtc: Add RTC class to machine module with sleep impl. The machine.RTC class is added and the machine module is updated with the implementation of sleep, deepsleep, reset_cause and wake_reason. --- ports/esp32/Makefile | 2 + ports/esp32/machine_rtc.c | 162 ++++++++++++++++++++++++++++++++++++++ ports/esp32/machine_rtc.h | 42 ++++++++++ ports/esp32/modmachine.c | 135 +++++++++++++++++++++++++++++++ ports/esp32/modmachine.h | 7 ++ ports/esp32/sdkconfig.h | 2 +- 6 files changed, 349 insertions(+), 1 deletion(-) create mode 100644 ports/esp32/machine_rtc.c create mode 100644 ports/esp32/machine_rtc.h diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 6bf212964c..3c70729fe3 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -152,6 +152,7 @@ SRC_C = \ machine_hw_spi.c \ machine_wdt.c \ mpthreadport.c \ + machine_rtc.c \ $(SRC_MOD) EXTMOD_SRC_C = $(addprefix extmod/,\ @@ -251,6 +252,7 @@ ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\ dport_access.o \ wifi_init.o \ wifi_internal.o \ + sleep_modes.o \ ) ESPIDF_HEAP_O = $(addprefix $(ESPCOMP)/heap/,\ diff --git a/ports/esp32/machine_rtc.c b/ports/esp32/machine_rtc.c new file mode 100644 index 0000000000..a701344229 --- /dev/null +++ b/ports/esp32/machine_rtc.c @@ -0,0 +1,162 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" + * Copyright (c) 2017 "Tom Manning" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include +#include +#include "driver/gpio.h" + +#include "py/nlr.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "timeutils.h" +#include "modmachine.h" +#include "machine_rtc.h" + +typedef struct _machine_rtc_obj_t { + mp_obj_base_t base; +} machine_rtc_obj_t; + +#define MEM_MAGIC 0x75507921 +/* There is 8K of rtc_slow_memory, but some is used by the system software + If the USER_MAXLEN is set to high, the following compile error will happen: + region `rtc_slow_seg' overflowed by N bytes + The current system software allows almost 4096 to be used. + To avoid running into issues if the system software uses more, 2048 was picked as a max length +*/ +#define MEM_USER_MAXLEN 2048 +RTC_DATA_ATTR uint32_t rtc_user_mem_magic; +RTC_DATA_ATTR uint32_t rtc_user_mem_len; +RTC_DATA_ATTR uint8_t rtc_user_mem_data[MEM_USER_MAXLEN]; + +// singleton RTC object +STATIC const machine_rtc_obj_t machine_rtc_obj = {{&machine_rtc_type}}; + +machine_rtc_config_t machine_rtc_config = { + .ext1_pins = 0, + .ext0_pin = -1 + }; + +STATIC mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // return constant object + return (mp_obj_t)&machine_rtc_obj; +} + +STATIC mp_obj_t machine_rtc_datetime_helper(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + // Get time + + struct timeval tv; + + gettimeofday(&tv, NULL); + timeutils_struct_time_t tm; + + timeutils_seconds_since_2000_to_struct_time(tv.tv_sec, &tm); + + mp_obj_t tuple[8] = { + mp_obj_new_int(tm.tm_year), + mp_obj_new_int(tm.tm_mon), + mp_obj_new_int(tm.tm_mday), + mp_obj_new_int(tm.tm_wday), + mp_obj_new_int(tm.tm_hour), + mp_obj_new_int(tm.tm_min), + mp_obj_new_int(tm.tm_sec), + mp_obj_new_int(tv.tv_usec) + }; + + return mp_obj_new_tuple(8, tuple); + } else { + // Set time + + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[1], 8, &items); + + struct timeval tv = {0}; + tv.tv_sec = timeutils_seconds_since_2000(mp_obj_get_int(items[0]), mp_obj_get_int(items[1]), mp_obj_get_int(items[2]), mp_obj_get_int(items[4]), mp_obj_get_int(items[5]), mp_obj_get_int(items[6])); + settimeofday(&tv, NULL); + + return mp_const_none; + } +} +STATIC mp_obj_t machine_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) { + return machine_rtc_datetime_helper(n_args, args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_datetime_obj, 1, 2, machine_rtc_datetime); + +STATIC mp_obj_t machine_rtc_init(mp_obj_t self_in, mp_obj_t date) { + mp_obj_t args[2] = {self_in, date}; + machine_rtc_datetime_helper(2, args); + + if (rtc_user_mem_magic != MEM_MAGIC) { + rtc_user_mem_magic = MEM_MAGIC; + rtc_user_mem_len = 0; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_rtc_init_obj, machine_rtc_init); + +STATIC mp_obj_t machine_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + // read RTC memory + uint32_t len = rtc_user_mem_len; + uint8_t rtcram[MEM_USER_MAXLEN]; + memcpy( (char *) rtcram, (char *) rtc_user_mem_data, len); + return mp_obj_new_bytes(rtcram, len); + } else { + // write RTC memory + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + + if (bufinfo.len > MEM_USER_MAXLEN) { + mp_raise_ValueError("buffer too long"); + } + memcpy( (char *) rtc_user_mem_data, (char *) bufinfo.buf, bufinfo.len); + rtc_user_mem_len = bufinfo.len; + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_memory_obj, 1, 2, machine_rtc_memory); + +STATIC const mp_map_elem_t machine_rtc_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&machine_rtc_datetime_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_datetime), (mp_obj_t)&machine_rtc_datetime_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_memory), (mp_obj_t)&machine_rtc_memory_obj }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_rtc_locals_dict, machine_rtc_locals_dict_table); + +const mp_obj_type_t machine_rtc_type = { + { &mp_type_type }, + .name = MP_QSTR_RTC, + .make_new = machine_rtc_make_new, + .locals_dict = (mp_obj_t)&machine_rtc_locals_dict, +}; diff --git a/ports/esp32/machine_rtc.h b/ports/esp32/machine_rtc.h new file mode 100644 index 0000000000..c2016ca792 --- /dev/null +++ b/ports/esp32/machine_rtc.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" + * Copyright (c) 2017 "Tom Manning" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_ESP32_MACHINE_RTC_H +#define MICROPY_INCLUDED_ESP32_MACHINE_RTC_H + +#include "modmachine.h" + +typedef struct { + uint64_t ext1_pins; // set bit == pin# + int8_t ext0_pin; // just the pin#, -1 == None + bool wake_on_touch : 1; + bool ext0_level : 1; + wake_type_t ext0_wake_types; + bool ext1_level : 1; +} machine_rtc_config_t; + +#endif diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index 32c9c5ad5f..72211a2c53 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -33,7 +33,9 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "rom/ets_sys.h" +#include "rom/rtc.h" #include "esp_system.h" +#include "driver/touch_pad.h" #include "py/obj.h" #include "py/runtime.h" @@ -43,9 +45,20 @@ #include "extmod/machine_i2c.h" #include "extmod/machine_spi.h" #include "modmachine.h" +#include "machine_rtc.h" #if MICROPY_PY_MACHINE +extern machine_rtc_config_t machine_rtc_config; + +typedef enum { + MP_PWRON_RESET = 1, + MP_HARD_RESET, + MP_WDT_RESET, + MP_DEEPSLEEP_RESET, + MP_SOFT_RESET +} reset_reason_t; + STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { if (n_args == 0) { // get @@ -64,6 +77,104 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 1, machine_freq); +STATIC mp_obj_t machine_sleep_helper(wake_type_t wake_type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + enum {ARG_sleep_ms}; + const mp_arg_t allowed_args[] = { + { MP_QSTR_sleep_ms, MP_ARG_INT, { .u_int = 0 } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + + mp_int_t expiry = args[ARG_sleep_ms].u_int; + + if (expiry != 0) { + esp_sleep_enable_timer_wakeup(expiry * 1000); + } + + if (machine_rtc_config.ext0_pin != -1 && (machine_rtc_config.ext0_wake_types & wake_type)) { + esp_sleep_enable_ext0_wakeup(machine_rtc_config.ext0_pin, machine_rtc_config.ext0_level ? 1 : 0); + } + + if (machine_rtc_config.ext1_pins != 0) { + esp_sleep_enable_ext1_wakeup( + machine_rtc_config.ext1_pins, + machine_rtc_config.ext1_level ? ESP_EXT1_WAKEUP_ANY_HIGH : ESP_EXT1_WAKEUP_ALL_LOW); + } + + if (machine_rtc_config.wake_on_touch) { + if (esp_sleep_enable_touchpad_wakeup() != ESP_OK) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "esp_sleep_enable_touchpad_wakeup() failed")); + } + } + + switch(wake_type) { + case MACHINE_WAKE_SLEEP: + esp_light_sleep_start(); + break; + case MACHINE_WAKE_DEEPSLEEP: + esp_deep_sleep_start(); + break; + } + return mp_const_none; +} + +STATIC mp_obj_t machine_sleep(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "light sleep not available for this version of ESP-IDF")); + return machine_sleep_helper(MACHINE_WAKE_SLEEP, n_args, pos_args, kw_args); +}; +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_sleep_obj, 0, machine_sleep); + +STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return machine_sleep_helper(MACHINE_WAKE_DEEPSLEEP, n_args, pos_args, kw_args); +}; +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_deepsleep_obj, 0, machine_deepsleep); + +STATIC mp_obj_t machine_reset_cause(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + switch(rtc_get_reset_reason(0)) { + case POWERON_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_PWRON_RESET); + break; + case SW_RESET: + case SW_CPU_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_SOFT_RESET); + break; + case OWDT_RESET: + case TG0WDT_SYS_RESET: + case TG1WDT_SYS_RESET: + case RTCWDT_SYS_RESET: + case RTCWDT_BROWN_OUT_RESET: + case RTCWDT_CPU_RESET: + case RTCWDT_RTC_RESET: + case TGWDT_CPU_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_WDT_RESET); + break; + + case DEEPSLEEP_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_DEEPSLEEP_RESET); + break; + + case EXT_CPU_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_HARD_RESET); + break; + + case NO_MEAN: + case SDIO_RESET: + case INTRUSION_RESET: + default: + return MP_OBJ_NEW_SMALL_INT(0); + break; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_reset_cause_obj, 0, machine_reset_cause); + +STATIC mp_obj_t machine_wake_reason(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return MP_OBJ_NEW_SMALL_INT(esp_sleep_get_wakeup_cause()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_wake_reason_obj, 0, machine_wake_reason); + STATIC mp_obj_t machine_reset(void) { esp_restart(); return mp_const_none; @@ -106,6 +217,8 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) }, { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) }, { MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) }, { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) }, @@ -115,6 +228,10 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) }, { MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&machine_wdt_type) }, + + // wake abilities + { MP_ROM_QSTR(MP_QSTR_SLEEP), MP_ROM_INT(MACHINE_WAKE_SLEEP) }, + { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) }, { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, { MP_ROM_QSTR(MP_QSTR_TouchPad), MP_ROM_PTR(&machine_touchpad_type) }, @@ -122,8 +239,26 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&machine_dac_type) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_pwm_type) }, + { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&machine_rtc_type) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&mp_machine_soft_spi_type) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) }, + + // Reset reasons + { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) }, + { MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(MP_HARD_RESET) }, + { MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(MP_PWRON_RESET) }, + { MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(MP_WDT_RESET) }, + { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_ROM_INT(MP_DEEPSLEEP_RESET) }, + { MP_ROM_QSTR(MP_QSTR_SOFT_RESET), MP_ROM_INT(MP_SOFT_RESET) }, + + // Wake reasons + { MP_ROM_QSTR(MP_QSTR_wake_reason), MP_ROM_PTR(&machine_wake_reason_obj) }, + { MP_ROM_QSTR(MP_QSTR_PIN_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT0) }, + { MP_ROM_QSTR(MP_QSTR_EXT0_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT0) }, + { MP_ROM_QSTR(MP_QSTR_EXT1_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT1) }, + { MP_ROM_QSTR(MP_QSTR_TIMER_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_TIMER) }, + { MP_ROM_QSTR(MP_QSTR_TOUCHPAD_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_TOUCHPAD) }, + { MP_ROM_QSTR(MP_QSTR_ULP_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_ULP) }, }; STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); diff --git a/ports/esp32/modmachine.h b/ports/esp32/modmachine.h index 58229007d7..c8513a4711 100644 --- a/ports/esp32/modmachine.h +++ b/ports/esp32/modmachine.h @@ -3,6 +3,12 @@ #include "py/obj.h" +typedef enum { + //MACHINE_WAKE_IDLE=0x01, + MACHINE_WAKE_SLEEP=0x02, + MACHINE_WAKE_DEEPSLEEP=0x04 +} wake_type_t; + extern const mp_obj_type_t machine_timer_type; extern const mp_obj_type_t machine_wdt_type; extern const mp_obj_type_t machine_pin_type; @@ -12,6 +18,7 @@ extern const mp_obj_type_t machine_dac_type; extern const mp_obj_type_t machine_pwm_type; extern const mp_obj_type_t machine_hw_spi_type; extern const mp_obj_type_t machine_uart_type; +extern const mp_obj_type_t machine_rtc_type; void machine_pins_init(void); void machine_pins_deinit(void); diff --git a/ports/esp32/sdkconfig.h b/ports/esp32/sdkconfig.h index 7fcbb7c019..3f5c7402a5 100644 --- a/ports/esp32/sdkconfig.h +++ b/ports/esp32/sdkconfig.h @@ -23,7 +23,7 @@ #define CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ 240 #define CONFIG_ESP32_DEFAULT_CPU_FREQ_240 1 #define CONFIG_ESP32_DEBUG_OCDAWARE 1 -#define CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY 0 +#define CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY 2000 #define CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE 1 #define CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE 1 #define CONFIG_ESP32_WIFI_AMPDU_ENABLED 1 From abec47a1cd4c26d073f717c8086ba21f64ff1aa3 Mon Sep 17 00:00:00 2001 From: Eric Poulsen Date: Thu, 15 Feb 2018 07:59:28 -0800 Subject: [PATCH 317/828] esp32/modesp32: Add new module "esp32" to support extra wake features. The machine.Pin class is also updated to support these wake-on-pin features. --- ports/esp32/Makefile | 1 + ports/esp32/machine_pin.c | 57 ++++++++++++--- ports/esp32/modesp32.c | 140 +++++++++++++++++++++++++++++++++++++ ports/esp32/modesp32.h | 29 ++++++++ ports/esp32/mpconfigport.h | 2 + 5 files changed, 221 insertions(+), 8 deletions(-) create mode 100644 ports/esp32/modesp32.c create mode 100644 ports/esp32/modesp32.h diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 3c70729fe3..02aebc1a63 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -147,6 +147,7 @@ SRC_C = \ network_lan.c \ modsocket.c \ modesp.c \ + modesp32.c \ moduhashlib.c \ espneopixel.c \ machine_hw_spi.c \ diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c index 493dff3f50..89ff9d8b77 100644 --- a/ports/esp32/machine_pin.c +++ b/ports/esp32/machine_pin.c @@ -35,6 +35,10 @@ #include "py/mphal.h" #include "modmachine.h" #include "extmod/virtpin.h" +#include "machine_rtc.h" +#include "modesp32.h" + +extern machine_rtc_config_t machine_rtc_config; typedef struct _machine_pin_obj_t { mp_obj_base_t base; @@ -219,10 +223,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_ // pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING) STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_handler, ARG_trigger, ARG_hard }; + enum { ARG_handler, ARG_trigger, ARG_wake }; static const mp_arg_t allowed_args[] = { { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_PIN_INTR_POSEDGE | GPIO_PIN_INTR_NEGEDGE} }, + { MP_QSTR_wake, MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; machine_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -232,14 +237,48 @@ STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_ // configure irq mp_obj_t handler = args[ARG_handler].u_obj; uint32_t trigger = args[ARG_trigger].u_int; - if (handler == mp_const_none) { - handler = MP_OBJ_NULL; - trigger = 0; + mp_obj_t wake_obj = args[ARG_wake].u_obj; + + if ((trigger == GPIO_PIN_INTR_LOLEVEL || trigger == GPIO_PIN_INTR_HILEVEL) && wake_obj != mp_const_none) { + mp_int_t wake; + if (mp_obj_get_int_maybe(wake_obj, &wake)) { + if (wake < 2 || wake > 7) { + mp_raise_ValueError("bad wake value"); + } + } else { + mp_raise_ValueError("bad wake value"); + } + + if (machine_rtc_config.wake_on_touch) { // not compatible + mp_raise_ValueError("no resources"); + } + + if (!RTC_IS_VALID_EXT_PIN(self->id)) { + mp_raise_ValueError("invalid pin for wake"); + } + + if (machine_rtc_config.ext0_pin == -1) { + machine_rtc_config.ext0_pin = self->id; + } else if (machine_rtc_config.ext0_pin != self->id) { + mp_raise_ValueError("no resources"); + } + + machine_rtc_config.ext0_level = trigger == GPIO_PIN_INTR_LOLEVEL ? 0 : 1; + machine_rtc_config.ext0_wake_types = wake; + } else { + if (machine_rtc_config.ext0_pin == self->id) { + machine_rtc_config.ext0_pin = -1; + } + + if (handler == mp_const_none) { + handler = MP_OBJ_NULL; + trigger = 0; + } + gpio_isr_handler_remove(self->id); + MP_STATE_PORT(machine_pin_irq_handler)[self->id] = handler; + gpio_set_intr_type(self->id, trigger); + gpio_isr_handler_add(self->id, machine_pin_isr_handler, (void*)self); } - gpio_isr_handler_remove(self->id); - MP_STATE_PORT(machine_pin_irq_handler)[self->id] = handler; - gpio_set_intr_type(self->id, trigger); - gpio_isr_handler_add(self->id, machine_pin_isr_handler, (void*)self); } // return the irq object @@ -261,6 +300,8 @@ STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULLDOWN_ONLY) }, { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_PIN_INTR_POSEDGE) }, { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_PIN_INTR_NEGEDGE) }, + { MP_ROM_QSTR(MP_QSTR_WAKE_LOW), MP_ROM_INT(GPIO_PIN_INTR_LOLEVEL) }, + { MP_ROM_QSTR(MP_QSTR_WAKE_HIGH), MP_ROM_INT(GPIO_PIN_INTR_HILEVEL) }, }; STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c new file mode 100644 index 0000000000..db78248f82 --- /dev/null +++ b/ports/esp32/modesp32.c @@ -0,0 +1,140 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include +#include +#include "driver/gpio.h" + +#include "py/nlr.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "timeutils.h" +#include "modmachine.h" +#include "machine_rtc.h" +#include "modesp32.h" + +extern machine_rtc_config_t machine_rtc_config; + +STATIC mp_obj_t esp32_wake_on_touch(const mp_obj_t wake) { + + if (machine_rtc_config.ext0_pin != -1) { + mp_raise_ValueError("no resources"); + } + //nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "touchpad wakeup not available for this version of ESP-IDF")); + + machine_rtc_config.wake_on_touch = mp_obj_is_true(wake); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_wake_on_touch_obj, esp32_wake_on_touch); + +STATIC mp_obj_t esp32_wake_on_ext0(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + if (machine_rtc_config.wake_on_touch) { + mp_raise_ValueError("no resources"); + } + enum {ARG_pin, ARG_level}; + const mp_arg_t allowed_args[] = { + { MP_QSTR_pin, MP_ARG_OBJ, {.u_obj = mp_obj_new_int(machine_rtc_config.ext0_pin)} }, + { MP_QSTR_level, MP_ARG_BOOL, {.u_bool = machine_rtc_config.ext0_level} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (args[ARG_pin].u_obj == mp_const_none) { + machine_rtc_config.ext0_pin = -1; // "None" + } else { + gpio_num_t pin_id = machine_pin_get_id(args[ARG_pin].u_obj); + if (pin_id != machine_rtc_config.ext0_pin) { + if (!RTC_IS_VALID_EXT_PIN(pin_id)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid pin")); + } + machine_rtc_config.ext0_pin = pin_id; + } + } + + machine_rtc_config.ext0_level = args[ARG_level].u_bool; + machine_rtc_config.ext0_wake_types = MACHINE_WAKE_SLEEP | MACHINE_WAKE_DEEPSLEEP; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_wake_on_ext0_obj, 0, esp32_wake_on_ext0); + +STATIC mp_obj_t esp32_wake_on_ext1(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum {ARG_pins, ARG_level}; + const mp_arg_t allowed_args[] = { + { MP_QSTR_pins, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_level, MP_ARG_BOOL, {.u_bool = machine_rtc_config.ext1_level} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + uint64_t ext1_pins = machine_rtc_config.ext1_pins; + + + // Check that all pins are allowed + if (args[ARG_pins].u_obj != mp_const_none) { + mp_uint_t len = 0; + mp_obj_t *elem; + mp_obj_get_array(args[ARG_pins].u_obj, &len, &elem); + ext1_pins = 0; + + for (int i = 0; i < len; i++) { + + gpio_num_t pin_id = machine_pin_get_id(elem[i]); + if (!RTC_IS_VALID_EXT_PIN(pin_id)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid pin")); + break; + } + ext1_pins |= (1ll << pin_id); + } + } + + machine_rtc_config.ext1_level = args[ARG_level].u_bool; + machine_rtc_config.ext1_pins = ext1_pins; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_wake_on_ext1_obj, 0, esp32_wake_on_ext1); + +STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp32) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_wake_on_touch), (mp_obj_t)&esp32_wake_on_touch_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_wake_on_ext0), (mp_obj_t)&esp32_wake_on_ext0_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_wake_on_ext1), (mp_obj_t)&esp32_wake_on_ext1_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_WAKEUP_ALL_LOW), mp_const_false }, + { MP_OBJ_NEW_QSTR(MP_QSTR_WAKEUP_ANY_HIGH), mp_const_true }, +}; + +STATIC MP_DEFINE_CONST_DICT(esp32_module_globals, esp32_module_globals_table); + +const mp_obj_module_t esp32_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&esp32_module_globals, +}; diff --git a/ports/esp32/modesp32.h b/ports/esp32/modesp32.h new file mode 100644 index 0000000000..83532e052f --- /dev/null +++ b/ports/esp32/modesp32.h @@ -0,0 +1,29 @@ +#ifndef MICROPY_INCLUDED_ESP32_MODESP32_H +#define MICROPY_INCLUDED_ESP32_MODESP32_H + +#define RTC_VALID_EXT_PINS \ +( \ + (1ll << 0) | \ + (1ll << 2) | \ + (1ll << 4) | \ + (1ll << 12) | \ + (1ll << 13) | \ + (1ll << 14) | \ + (1ll << 15) | \ + (1ll << 25) | \ + (1ll << 26) | \ + (1ll << 27) | \ + (1ll << 32) | \ + (1ll << 33) | \ + (1ll << 34) | \ + (1ll << 35) | \ + (1ll << 36) | \ + (1ll << 37) | \ + (1ll << 38) | \ + (1ll << 39) \ +) + +#define RTC_LAST_EXT_PIN 39 +#define RTC_IS_VALID_EXT_PIN(pin_id) ((1ll << (pin_id)) & RTC_VALID_EXT_PINS) + +#endif // MICROPY_INCLUDED_ESP32_MODESP32_H diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 69d17fd818..e5fc2b4c5d 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -162,6 +162,7 @@ // extra built in modules to add to the list of known ones extern const struct _mp_obj_module_t esp_module; +extern const struct _mp_obj_module_t esp32_module; extern const struct _mp_obj_module_t utime_module; extern const struct _mp_obj_module_t uos_module; extern const struct _mp_obj_module_t mp_module_usocket; @@ -171,6 +172,7 @@ extern const struct _mp_obj_module_t mp_module_onewire; #define MICROPY_PORT_BUILTIN_MODULES \ { MP_OBJ_NEW_QSTR(MP_QSTR_esp), (mp_obj_t)&esp_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_esp32), (mp_obj_t)&esp32_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_utime), (mp_obj_t)&utime_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&uos_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_usocket), (mp_obj_t)&mp_module_usocket }, \ From 60c6b880fa4077a05d1273606d41fdc33f06bc2b Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 17 Feb 2018 00:52:55 +1100 Subject: [PATCH 318/828] esp32/machine_rtc: Move export declaration from .c to common .h file. --- ports/esp32/machine_pin.c | 2 -- ports/esp32/machine_rtc.h | 2 ++ ports/esp32/modesp32.c | 2 -- ports/esp32/modmachine.c | 2 -- 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c index 89ff9d8b77..2a26d6bfb0 100644 --- a/ports/esp32/machine_pin.c +++ b/ports/esp32/machine_pin.c @@ -38,8 +38,6 @@ #include "machine_rtc.h" #include "modesp32.h" -extern machine_rtc_config_t machine_rtc_config; - typedef struct _machine_pin_obj_t { mp_obj_base_t base; gpio_num_t id; diff --git a/ports/esp32/machine_rtc.h b/ports/esp32/machine_rtc.h index c2016ca792..e34deb9be6 100644 --- a/ports/esp32/machine_rtc.h +++ b/ports/esp32/machine_rtc.h @@ -39,4 +39,6 @@ typedef struct { bool ext1_level : 1; } machine_rtc_config_t; +extern machine_rtc_config_t machine_rtc_config; + #endif diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c index db78248f82..6d18e0add1 100644 --- a/ports/esp32/modesp32.c +++ b/ports/esp32/modesp32.c @@ -40,8 +40,6 @@ #include "machine_rtc.h" #include "modesp32.h" -extern machine_rtc_config_t machine_rtc_config; - STATIC mp_obj_t esp32_wake_on_touch(const mp_obj_t wake) { if (machine_rtc_config.ext0_pin != -1) { diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index 72211a2c53..2d59e137ef 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -49,8 +49,6 @@ #if MICROPY_PY_MACHINE -extern machine_rtc_config_t machine_rtc_config; - typedef enum { MP_PWRON_RESET = 1, MP_HARD_RESET, From 5591bd237a69a3a1a6ac03cb1dc9edcde835f708 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Tue, 13 Feb 2018 22:00:20 +0100 Subject: [PATCH 319/828] py/nlrthumb: Do not mark nlr_push as not returning anything. By adding __builtin_unreachable() at the end of nlr_push, we're essentially telling the compiler that this function will never return. When GCC LTO is in use, this means that any time nlr_push() is called (which is often), the compiler thinks this function will never return and thus eliminates all code following the call. Note: I've added a 'return 0' for older GCC versions like 4.6 which complain about not returning anything (which doesn't make sense in a naked function). Newer GCC versions (tested 4.8, 5.4 and some others) don't complain about this. --- py/nlrthumb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/py/nlrthumb.c b/py/nlrthumb.c index fb0a92236f..7dbeac1b67 100644 --- a/py/nlrthumb.c +++ b/py/nlrthumb.c @@ -76,9 +76,9 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { #endif ); - #if defined(__GNUC__) + #if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)) // Older versions of gcc give an error when naked functions don't return a value - __builtin_unreachable(); + return 0; #endif } From 3759aa2cc98c96b869f3db5c4ac51778d3726669 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 18 Feb 2018 23:40:54 +1100 Subject: [PATCH 320/828] drivers/sdcard: Update SD mounting example code for ESP8266. --- drivers/sdcard/sdcard.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/sdcard/sdcard.py b/drivers/sdcard/sdcard.py index 719eb982e2..8f28b476e2 100644 --- a/drivers/sdcard/sdcard.py +++ b/drivers/sdcard/sdcard.py @@ -15,9 +15,8 @@ Example usage on ESP8266: import machine, sdcard, os sd = sdcard.SDCard(machine.SPI(1), machine.Pin(15)) - os.umount() - os.VfsFat(sd, "") - os.listdir() + os.mount(sd, '/sd') + os.listdir('/') """ From 7b2a9b059a4c60252b37f61cdbc2a28e375438a5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 19 Feb 2018 00:26:14 +1100 Subject: [PATCH 321/828] py/pystack: Use "pystack exhausted" as error msg for out of pystack mem. Using the message "maximum recursion depth exceeded" for when the pystack runs out of memory can be misleading because the pystack can run out for reasons other than deep recursion (although in most cases pystack exhaustion is probably indirectly related to deep recursion). And it's important to give the user more precise feedback as to the reason for the error: if they know precisely that the pystack was exhausted then they have a chance to increase the amount of memory available to the pystack (as opposed to not knowing if it was the C stack or pystack that ran out). Also, C stack exhaustion is more serious than pystack exhaustion because it could have been that the C stack overflowed and overwrote/corrupted some data and so the system must be restarted. The pystack can never corrupt data in this way so pystack exhaustion does not require a system restart. Knowing the difference between these two cases is therefore important. The actual exception type for pystack exhaustion remains as RuntimeError so that programatically it behaves the same as a C stack exhaustion. --- py/pystack.c | 3 ++- py/qstrdefs.h | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/py/pystack.c b/py/pystack.c index 767c307e9a..552e59d537 100644 --- a/py/pystack.c +++ b/py/pystack.c @@ -43,7 +43,8 @@ void *mp_pystack_alloc(size_t n_bytes) { #endif if (MP_STATE_THREAD(pystack_cur) + n_bytes > MP_STATE_THREAD(pystack_end)) { // out of memory in the pystack - mp_raise_recursion_depth(); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError, + MP_OBJ_NEW_QSTR(MP_QSTR_pystack_space_exhausted))); } void *ptr = MP_STATE_THREAD(pystack_cur); MP_STATE_THREAD(pystack_cur) += n_bytes; diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 1b480c9c75..a609058120 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -52,3 +52,7 @@ Q() Q() Q() Q(utf-8) + +#if MICROPY_ENABLE_PYSTACK +Q(pystack exhausted) +#endif From 5a82ba8e073f847985595a46fb2f0c12f4389bbc Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 19 Feb 2018 00:36:55 +1100 Subject: [PATCH 322/828] esp32/machine_touchpad: Swap pins 32 and 33. Based on testing, this is how the mapping should be. --- ports/esp32/machine_touchpad.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/esp32/machine_touchpad.c b/ports/esp32/machine_touchpad.c index 96de1a2a1d..ff31ccf69a 100644 --- a/ports/esp32/machine_touchpad.c +++ b/ports/esp32/machine_touchpad.c @@ -51,8 +51,8 @@ STATIC const mtp_obj_t touchpad_obj[] = { {{&machine_touchpad_type}, GPIO_NUM_12, TOUCH_PAD_NUM5}, {{&machine_touchpad_type}, GPIO_NUM_14, TOUCH_PAD_NUM6}, {{&machine_touchpad_type}, GPIO_NUM_27, TOUCH_PAD_NUM7}, - {{&machine_touchpad_type}, GPIO_NUM_33, TOUCH_PAD_NUM8}, - {{&machine_touchpad_type}, GPIO_NUM_32, TOUCH_PAD_NUM9}, + {{&machine_touchpad_type}, GPIO_NUM_32, TOUCH_PAD_NUM8}, + {{&machine_touchpad_type}, GPIO_NUM_33, TOUCH_PAD_NUM9}, }; STATIC mp_obj_t mtp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, From a3e01d3642d6c287bf2d0c14b3d75bf305327819 Mon Sep 17 00:00:00 2001 From: Mike Wadsten Date: Sun, 18 Feb 2018 21:51:04 -0600 Subject: [PATCH 323/828] py/objdict: Disallow possible modifications to fixed dicts. --- py/objdict.c | 13 +++++++++ tests/basics/dict_fixed.py | 48 ++++++++++++++++++++++++++++++++++ tests/basics/dict_fixed.py.exp | 7 +++++ 3 files changed, 68 insertions(+) create mode 100644 tests/basics/dict_fixed.py create mode 100644 tests/basics/dict_fixed.py.exp diff --git a/py/objdict.c b/py/objdict.c index f6fb594b3c..c0647067a1 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -195,9 +195,16 @@ STATIC mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { /******************************************************************************/ /* dict methods */ +STATIC void mp_ensure_not_fixed(const mp_obj_dict_t *dict) { + if (dict->map.is_fixed) { + mp_raise_TypeError(NULL); + } +} + STATIC mp_obj_t dict_clear(mp_obj_t self_in) { mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); + mp_ensure_not_fixed(self); mp_map_clear(&self->map); @@ -253,6 +260,9 @@ STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(dict_fromkeys_obj, MP_ROM_PTR(&dict_fromk STATIC mp_obj_t dict_get_helper(size_t n_args, const mp_obj_t *args, mp_map_lookup_kind_t lookup_kind) { mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0])); mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]); + if (lookup_kind != MP_MAP_LOOKUP) { + mp_ensure_not_fixed(self); + } mp_map_elem_t *elem = mp_map_lookup(&self->map, args[1], lookup_kind); mp_obj_t value; if (elem == NULL || elem->value == MP_OBJ_NULL) { @@ -295,6 +305,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_setdefault_obj, 2, 3, dict_setde STATIC mp_obj_t dict_popitem(mp_obj_t self_in) { mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); + mp_ensure_not_fixed(self); size_t cur = 0; mp_map_elem_t *next = dict_iter_next(self, &cur); if (next == NULL) { @@ -313,6 +324,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_popitem_obj, dict_popitem); STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0])); mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]); + mp_ensure_not_fixed(self); mp_arg_check_num(n_args, kwargs->used, 1, 2, true); @@ -578,6 +590,7 @@ size_t mp_obj_dict_len(mp_obj_t self_in) { mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) { mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); + mp_ensure_not_fixed(self); mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; return self_in; } diff --git a/tests/basics/dict_fixed.py b/tests/basics/dict_fixed.py new file mode 100644 index 0000000000..4261a06557 --- /dev/null +++ b/tests/basics/dict_fixed.py @@ -0,0 +1,48 @@ +# test that fixed dictionaries cannot be modified + +try: + import uerrno +except ImportError: + print("SKIP") + raise SystemExit + +# Save a copy of uerrno.errorcode, so we can check later +# that it hasn't been modified. +errorcode_copy = uerrno.errorcode.copy() + +try: + uerrno.errorcode.popitem() +except TypeError: + print("TypeError") + +try: + uerrno.errorcode.pop(0) +except TypeError: + print("TypeError") + +try: + uerrno.errorcode.setdefault(0, 0) +except TypeError: + print("TypeError") + +try: + uerrno.errorcode.update([(1, 2)]) +except TypeError: + print("TypeError") + +try: + del uerrno.errorcode[1] +except TypeError: + print("TypeError") + +try: + uerrno.errorcode[1] = 'foo' +except TypeError: + print("TypeError") + +try: + uerrno.errorcode.clear() +except TypeError: + print("TypeError") + +assert uerrno.errorcode == errorcode_copy diff --git a/tests/basics/dict_fixed.py.exp b/tests/basics/dict_fixed.py.exp new file mode 100644 index 0000000000..ffaeb4085c --- /dev/null +++ b/tests/basics/dict_fixed.py.exp @@ -0,0 +1,7 @@ +TypeError +TypeError +TypeError +TypeError +TypeError +TypeError +TypeError From ea7cf2b738c3b103b472547500fb0107b956fc0c Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Sat, 27 Jan 2018 18:37:38 +0100 Subject: [PATCH 324/828] py/gc: Reduce code size by specialising VERIFY_MARK_AND_PUSH macro. This macro is written out explicitly in the two locations that it is used and then the code is optimised, opening possibilities for further optimisations and reducing code size: unix: -48 minimal CROSS=1: -32 stm32: -32 --- py/gc.c | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/py/gc.c b/py/gc.c index 5196954e2e..9089a26be1 100644 --- a/py/gc.c +++ b/py/gc.c @@ -203,24 +203,6 @@ bool gc_is_locked(void) { #endif #endif -// ptr should be of type void* -#define VERIFY_MARK_AND_PUSH(ptr) \ - do { \ - if (VERIFY_PTR(ptr)) { \ - size_t _block = BLOCK_FROM_PTR(ptr); \ - if (ATB_GET_KIND(_block) == AT_HEAD) { \ - /* an unmarked head, mark it, and push it on gc stack */ \ - TRACE_MARK(_block, ptr); \ - ATB_HEAD_TO_MARK(_block); \ - if (MP_STATE_MEM(gc_sp) < &MP_STATE_MEM(gc_stack)[MICROPY_ALLOC_GC_STACK_SIZE]) { \ - *MP_STATE_MEM(gc_sp)++ = _block; \ - } else { \ - MP_STATE_MEM(gc_stack_overflow) = 1; \ - } \ - } \ - } \ - } while (0) - STATIC void gc_drain_stack(void) { while (MP_STATE_MEM(gc_sp) > MP_STATE_MEM(gc_stack)) { // pop the next block off the stack @@ -236,7 +218,20 @@ STATIC void gc_drain_stack(void) { void **ptrs = (void**)PTR_FROM_BLOCK(block); for (size_t i = n_blocks * BYTES_PER_BLOCK / sizeof(void*); i > 0; i--, ptrs++) { void *ptr = *ptrs; - VERIFY_MARK_AND_PUSH(ptr); + if (VERIFY_PTR(ptr)) { + // Mark and push this pointer + size_t childblock = BLOCK_FROM_PTR(ptr); + if (ATB_GET_KIND(childblock) == AT_HEAD) { + // an unmarked head, mark it, and push it on gc stack + TRACE_MARK(childblock, ptr); + ATB_HEAD_TO_MARK(childblock); + if (MP_STATE_MEM(gc_sp) < &MP_STATE_MEM(gc_stack)[MICROPY_ALLOC_GC_STACK_SIZE]) { + *MP_STATE_MEM(gc_sp)++ = childblock; + } else { + MP_STATE_MEM(gc_stack_overflow) = 1; + } + } + } } } } @@ -337,8 +332,17 @@ void gc_collect_start(void) { void gc_collect_root(void **ptrs, size_t len) { for (size_t i = 0; i < len; i++) { void *ptr = ptrs[i]; - VERIFY_MARK_AND_PUSH(ptr); - gc_drain_stack(); + if (VERIFY_PTR(ptr)) { + // Mark and push this pointer + size_t block = BLOCK_FROM_PTR(ptr); + if (ATB_GET_KIND(block) == AT_HEAD) { + // an unmarked head, mark it, and push it on gc stack + TRACE_MARK(block, ptr); + ATB_HEAD_TO_MARK(block); + *MP_STATE_MEM(gc_sp)++ = block; + gc_drain_stack(); + } + } } } From 5c9e5618e088ddc233cd3bd1b1f48572ab403983 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Thu, 15 Feb 2018 17:10:13 +0100 Subject: [PATCH 325/828] py/gc: Rename gc_drain_stack to gc_mark_subtree and pass it first block. This saves a bit in code size: minimal CROSS=1: -44 unix: -96 --- py/gc.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/py/gc.c b/py/gc.c index 9089a26be1..616ff783f5 100644 --- a/py/gc.c +++ b/py/gc.c @@ -203,11 +203,13 @@ bool gc_is_locked(void) { #endif #endif -STATIC void gc_drain_stack(void) { - while (MP_STATE_MEM(gc_sp) > MP_STATE_MEM(gc_stack)) { - // pop the next block off the stack - size_t block = *--MP_STATE_MEM(gc_sp); - +// Take the given block as the topmost block on the stack. Check all it's +// children: mark the unmarked child blocks and put those newly marked +// blocks on the stack. When all children have been checked, pop off the +// topmost block on the stack and repeat with that one. +STATIC void gc_mark_subtree(size_t block) { + // Start with the block passed in the argument. + for (;;) { // work out number of consecutive blocks in the chain starting with this one size_t n_blocks = 0; do { @@ -233,6 +235,14 @@ STATIC void gc_drain_stack(void) { } } } + + // Are there any blocks on the stack? + if (MP_STATE_MEM(gc_sp) <= MP_STATE_MEM(gc_stack)) { + break; // No, stack is empty, we're done. + } + + // pop the next block off the stack + block = *--MP_STATE_MEM(gc_sp); } } @@ -245,8 +255,7 @@ STATIC void gc_deal_with_stack_overflow(void) { for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) { // trace (again) if mark bit set if (ATB_GET_KIND(block) == AT_MARK) { - *MP_STATE_MEM(gc_sp)++ = block; - gc_drain_stack(); + gc_mark_subtree(block); } } } @@ -339,8 +348,7 @@ void gc_collect_root(void **ptrs, size_t len) { // an unmarked head, mark it, and push it on gc stack TRACE_MARK(block, ptr); ATB_HEAD_TO_MARK(block); - *MP_STATE_MEM(gc_sp)++ = block; - gc_drain_stack(); + gc_mark_subtree(block); } } } From 736faef2233fe9c721b940a108b28808d4c7f7a0 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Thu, 15 Feb 2018 17:22:34 +0100 Subject: [PATCH 326/828] py/gc: Make GC stack pointer a local variable. This saves a bit in code size, and saves some precious .bss RAM: .text .bss minimal CROSS=1: -28 -4 unix (64-bit): -64 -8 --- py/gc.c | 11 +++++------ py/mpstate.h | 1 - 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/py/gc.c b/py/gc.c index 616ff783f5..92f6348cbe 100644 --- a/py/gc.c +++ b/py/gc.c @@ -209,6 +209,7 @@ bool gc_is_locked(void) { // topmost block on the stack and repeat with that one. STATIC void gc_mark_subtree(size_t block) { // Start with the block passed in the argument. + size_t sp = 0; for (;;) { // work out number of consecutive blocks in the chain starting with this one size_t n_blocks = 0; @@ -227,8 +228,8 @@ STATIC void gc_mark_subtree(size_t block) { // an unmarked head, mark it, and push it on gc stack TRACE_MARK(childblock, ptr); ATB_HEAD_TO_MARK(childblock); - if (MP_STATE_MEM(gc_sp) < &MP_STATE_MEM(gc_stack)[MICROPY_ALLOC_GC_STACK_SIZE]) { - *MP_STATE_MEM(gc_sp)++ = childblock; + if (sp < MICROPY_ALLOC_GC_STACK_SIZE) { + MP_STATE_MEM(gc_stack)[sp++] = childblock; } else { MP_STATE_MEM(gc_stack_overflow) = 1; } @@ -237,19 +238,18 @@ STATIC void gc_mark_subtree(size_t block) { } // Are there any blocks on the stack? - if (MP_STATE_MEM(gc_sp) <= MP_STATE_MEM(gc_stack)) { + if (sp == 0) { break; // No, stack is empty, we're done. } // pop the next block off the stack - block = *--MP_STATE_MEM(gc_sp); + block = MP_STATE_MEM(gc_stack)[--sp]; } } STATIC void gc_deal_with_stack_overflow(void) { while (MP_STATE_MEM(gc_stack_overflow)) { MP_STATE_MEM(gc_stack_overflow) = 0; - MP_STATE_MEM(gc_sp) = MP_STATE_MEM(gc_stack); // scan entire memory looking for blocks which have been marked but not their children for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) { @@ -323,7 +323,6 @@ void gc_collect_start(void) { MP_STATE_MEM(gc_alloc_amount) = 0; #endif MP_STATE_MEM(gc_stack_overflow) = 0; - MP_STATE_MEM(gc_sp) = MP_STATE_MEM(gc_stack); // Trace root pointers. This relies on the root pointers being organised // correctly in the mp_state_ctx structure. We scan nlr_top, dict_locals, diff --git a/py/mpstate.h b/py/mpstate.h index 45e89590f7..a7ffbbf3cb 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -78,7 +78,6 @@ typedef struct _mp_state_mem_t { int gc_stack_overflow; size_t gc_stack[MICROPY_ALLOC_GC_STACK_SIZE]; - size_t *gc_sp; uint16_t gc_lock_depth; // This variable controls auto garbage collection. If set to 0 then the From 2a0cbc0d38e8e342c9a54c66a0cca10cae371c6a Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 19 Feb 2018 16:08:20 +1100 Subject: [PATCH 327/828] py/gc: Update comment now that gc_drain_stack is called gc_mark_subtree. --- py/gc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/py/gc.c b/py/gc.c index 92f6348cbe..84c9918fd7 100644 --- a/py/gc.c +++ b/py/gc.c @@ -341,10 +341,9 @@ void gc_collect_root(void **ptrs, size_t len) { for (size_t i = 0; i < len; i++) { void *ptr = ptrs[i]; if (VERIFY_PTR(ptr)) { - // Mark and push this pointer size_t block = BLOCK_FROM_PTR(ptr); if (ATB_GET_KIND(block) == AT_HEAD) { - // an unmarked head, mark it, and push it on gc stack + // An unmarked head: mark it, and mark all its children TRACE_MARK(block, ptr); ATB_HEAD_TO_MARK(block); gc_mark_subtree(block); From a8775aaeb053b268cddd629105f02b014df47f64 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Feb 2018 18:12:01 +1100 Subject: [PATCH 328/828] py/qstr: Add QSTR_TOTAL() macro to get number of qstrs. --- py/qstr.h | 1 + 1 file changed, 1 insertion(+) diff --git a/py/qstr.h b/py/qstr.h index 63fd0c369f..f4375ee0e9 100644 --- a/py/qstr.h +++ b/py/qstr.h @@ -56,6 +56,7 @@ typedef struct _qstr_pool_t { } qstr_pool_t; #define QSTR_FROM_STR_STATIC(s) (qstr_from_strn((s), strlen(s))) +#define QSTR_TOTAL() (MP_STATE_VM(last_pool)->total_prev_len + MP_STATE_VM(last_pool)->len) void qstr_init(void); From 98647e83c733a8a8d36522f71e677367ca8ddd03 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Feb 2018 18:12:27 +1100 Subject: [PATCH 329/828] py/modbuiltins: Simplify and generalise dir() by probing qstrs. This patch improves the builtin dir() function by probing the target object with all possible qstrs via mp_load_method_maybe. This is very simple (in terms of implementation), doesn't require recursion, and allows to list all methods of user-defined classes (without duplicates) even if they have multiple inheritance with a common parent. The downside is that it can be slow because it has to iterate through all the qstrs in the system, but the "dir()" function is anyway mostly used for testing frameworks and user introspection of types, so speed is not considered a priority. In addition to providing a more complete implementation of dir(), this patch is simpler than the previous implementation and saves some code space: bare-arm: -80 minimal x86: -80 unix x64: -56 unix nanbox: -48 stm32: -80 cc3200: -80 esp8266: -104 esp32: -64 --- py/modbuiltins.c | 46 ++++++++++--------------------------- tests/basics/builtin_dir.py | 19 +++++++++++++++ 2 files changed, 31 insertions(+), 34 deletions(-) diff --git a/py/modbuiltins.c b/py/modbuiltins.c index 5461816af0..5d4ec8ffe4 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -173,46 +173,24 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_chr_obj, mp_builtin_chr); STATIC mp_obj_t mp_builtin_dir(size_t n_args, const mp_obj_t *args) { - // TODO make this function more general and less of a hack - - mp_obj_dict_t *dict = NULL; - mp_map_t *members = NULL; - if (n_args == 0) { - // make a list of names in the local name space - dict = mp_locals_get(); - } else { // n_args == 1 - // make a list of names in the given object - if (MP_OBJ_IS_TYPE(args[0], &mp_type_module)) { - dict = mp_obj_module_get_globals(args[0]); - } else { - mp_obj_type_t *type; - if (MP_OBJ_IS_TYPE(args[0], &mp_type_type)) { - type = MP_OBJ_TO_PTR(args[0]); - } else { - type = mp_obj_get_type(args[0]); - } - if (type->locals_dict != NULL && type->locals_dict->base.type == &mp_type_dict) { - dict = type->locals_dict; - } - } - if (mp_obj_is_instance_type(mp_obj_get_type(args[0]))) { - mp_obj_instance_t *inst = MP_OBJ_TO_PTR(args[0]); - members = &inst->members; - } - } - mp_obj_t dir = mp_obj_new_list(0, NULL); - if (dict != NULL) { + if (n_args == 0) { + // Make a list of names in the local namespace + mp_obj_dict_t *dict = mp_locals_get(); for (size_t i = 0; i < dict->map.alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { mp_obj_list_append(dir, dict->map.table[i].key); } } - } - if (members != NULL) { - for (size_t i = 0; i < members->alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(members, i)) { - mp_obj_list_append(dir, members->table[i].key); + } else { // n_args == 1 + // Make a list of names in the given object + // Implemented by probing all possible qstrs with mp_load_method_maybe + size_t nqstr = QSTR_TOTAL(); + for (size_t i = 1; i < nqstr; ++i) { + mp_obj_t dest[2]; + mp_load_method_maybe(args[0], i, dest); + if (dest[0] != MP_OBJ_NULL) { + mp_obj_list_append(dir, MP_OBJ_NEW_QSTR(i)); } } } diff --git a/tests/basics/builtin_dir.py b/tests/basics/builtin_dir.py index 16e7e669e4..c15a76f4c6 100644 --- a/tests/basics/builtin_dir.py +++ b/tests/basics/builtin_dir.py @@ -17,3 +17,22 @@ foo = Foo() print('__init__' in dir(foo)) print('x' in dir(foo)) +# dir of subclass +class A: + def a(): + pass +class B(A): + def b(): + pass +d = dir(B()) +print(d.count('a'), d.count('b')) + +# dir of class with multiple bases and a common parent +class C(A): + def c(): + pass +class D(B, C): + def d(): + pass +d = dir(D()) +print(d.count('a'), d.count('b'), d.count('c'), d.count('d')) From 165aab12a3918004325238c794e27e7f4adbb401 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Feb 2018 18:12:31 +1100 Subject: [PATCH 330/828] py/repl: Generalise REPL autocomplete to use qstr probing. This patch changes the way REPL autocomplete finds matches. It now probes the target object for all qstrs via mp_load_method_maybe to look for a match with the given input string. Similar to how the builtin dir() function works, this new algorithm now find all methods and instances of user-defined classes including attributes of their parent classes. This helps a lot at the REPL prompt for user-discovery and to autocomplete names even for classes that are derived. The downside is that this new algorithm is slower than the previous one, and in particular will be slower the more qstrs there are in the system. But because REPL autocomplete is primarily used in an interactive way it is not that important to make it fast, as long as it is "fast enough" compared to human reaction. On a slow microcontroller (CPU running at 16MHz) the autocomplete time for a list of 35 names in the outer namespace (pressing tab at a bare prompt) takes about 160ms with this algorithm, compared to about 40ms for the previous implementation (this time includes the actual printing of the names as well). This time of 160ms is very reasonable especially given the new functionality of listing all the names. This patch also decreases code size by: bare-arm: +0 minimal x86: -128 unix x64: -128 unix nanbox: -224 stm32: -88 cc3200: -80 esp8266: -92 esp32: -84 --- py/repl.c | 78 +++++++++++--------------- tests/cmdline/repl_autocomplete.py | 3 +- tests/cmdline/repl_autocomplete.py.exp | 3 +- tests/unix/extra_coverage.py.exp | 10 ++-- 4 files changed, 39 insertions(+), 55 deletions(-) diff --git a/py/repl.c b/py/repl.c index 7e8922e19a..61ae2c1fef 100644 --- a/py/repl.c +++ b/py/repl.c @@ -27,6 +27,7 @@ #include #include "py/obj.h" #include "py/runtime.h" +#include "py/builtin.h" #include "py/repl.h" #if MICROPY_HELPER_REPL @@ -136,8 +137,11 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print } } - // begin search in locals dict - mp_obj_dict_t *dict = mp_locals_get(); + size_t nqstr = QSTR_TOTAL(); + + // begin search in outer global dict which is accessed from __main__ + mp_obj_t obj = MP_OBJ_FROM_PTR(&mp_module___main__); + mp_obj_t dest[2]; for (;;) { // get next word in string to complete @@ -148,43 +152,20 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print size_t s_len = str - s_start; if (str < top) { - // a complete word, lookup in current dict - - mp_obj_t obj = MP_OBJ_NULL; - for (size_t i = 0; i < dict->map.alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { - size_t d_len; - const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); - if (s_len == d_len && strncmp(s_start, d_str, d_len) == 0) { - obj = dict->map.table[i].value; - break; - } - } + // a complete word, lookup in current object + qstr q = qstr_find_strn(s_start, s_len); + if (q == MP_QSTR_NULL) { + // lookup will fail + return 0; } + mp_load_method_maybe(obj, q, dest); + obj = dest[0]; // attribute, method, or MP_OBJ_NULL if nothing found if (obj == MP_OBJ_NULL) { // lookup failed return 0; } - // found an object of this name; try to get its dict - if (MP_OBJ_IS_TYPE(obj, &mp_type_module)) { - dict = mp_obj_module_get_globals(obj); - } else { - mp_obj_type_t *type; - if (MP_OBJ_IS_TYPE(obj, &mp_type_type)) { - type = MP_OBJ_TO_PTR(obj); - } else { - type = mp_obj_get_type(obj); - } - if (type->locals_dict != NULL && type->locals_dict->base.type == &mp_type_dict) { - dict = type->locals_dict; - } else { - // obj has no dict - return 0; - } - } - // skip '.' to move to next word ++str; @@ -192,14 +173,15 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print // end of string, do completion on this partial name // look for matches - int n_found = 0; const char *match_str = NULL; size_t match_len = 0; - for (size_t i = 0; i < dict->map.alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { - size_t d_len; - const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); - if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { + qstr q_first = 0, q_last; + for (qstr q = 1; q < nqstr; ++q) { + size_t d_len; + const char *d_str = (const char*)qstr_data(q, &d_len); + if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { + mp_load_method_maybe(obj, q, dest); + if (dest[0] != MP_OBJ_NULL) { if (match_str == NULL) { match_str = d_str; match_len = d_len; @@ -213,13 +195,16 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print } } } - ++n_found; + if (q_first == 0) { + q_first = q; + } + q_last = q; } } } // nothing found - if (n_found == 0) { + if (q_first == 0) { // If there're no better alternatives, and if it's first word // in the line, try to complete "import". if (s_start == org_str) { @@ -234,7 +219,7 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print } // 1 match found, or multiple matches with a common prefix - if (n_found == 1 || match_len > s_len) { + if (q_first == q_last || match_len > s_len) { *compl_str = match_str + s_len; return match_len - s_len; } @@ -245,11 +230,12 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print #define MAX_LINE_LEN (4 * WORD_SLOT_LEN) int line_len = MAX_LINE_LEN; // force a newline for first word - for (size_t i = 0; i < dict->map.alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { - size_t d_len; - const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); - if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { + for (qstr q = q_first; q <= q_last; ++q) { + size_t d_len; + const char *d_str = (const char*)qstr_data(q, &d_len); + if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { + mp_load_method_maybe(obj, q, dest); + if (dest[0] != MP_OBJ_NULL) { int gap = (line_len + WORD_SLOT_LEN - 1) / WORD_SLOT_LEN * WORD_SLOT_LEN - line_len; if (gap < 2) { gap += WORD_SLOT_LEN; diff --git a/tests/cmdline/repl_autocomplete.py b/tests/cmdline/repl_autocomplete.py index a848cab0f6..27cad428f7 100644 --- a/tests/cmdline/repl_autocomplete.py +++ b/tests/cmdline/repl_autocomplete.py @@ -6,5 +6,4 @@ x = '123' 1, x.isdi () i = str i.lowe ('ABC') -j = None -j.  +None.  diff --git a/tests/cmdline/repl_autocomplete.py.exp b/tests/cmdline/repl_autocomplete.py.exp index dfb998ff6e..75002985e3 100644 --- a/tests/cmdline/repl_autocomplete.py.exp +++ b/tests/cmdline/repl_autocomplete.py.exp @@ -10,6 +10,5 @@ Use \.\+ >>> i = str >>> i.lower('ABC') 'abc' ->>> j = None ->>> j. +>>> None. >>> diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index 26fd2e332d..8a2c6aea90 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -24,11 +24,11 @@ RuntimeError: # repl ame__ -__name__ path argv version -version_info implementation platform byteorder -maxsize exit stdin stdout -stderr modules exc_info getsizeof -print_exception +__class__ __name__ argv byteorder +exc_info exit getsizeof implementation +maxsize modules path platform +print_exception stderr stdin +stdout version version_info ementation # attrtuple (start=1, stop=2, step=3) From 4e469085c192017c5244bbc115bac90f4bb667cb Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 19 Feb 2018 16:25:30 +1100 Subject: [PATCH 331/828] py/objstr: Protect against creating bytes(n) with n negative. Prior to this patch uPy (on a 32-bit arch) would have severe issues when calling bytes(-1): such a call would call vstr_init_len(vstr, -1) which would then +1 on the len and call vstr_init(vstr, 0), which would then round this up and allocate a small amount of memory for the vstr. The bytes constructor would then attempt to zero out all this memory, thinking it had allocated 2^32-1 bytes. --- py/objstr.c | 5 ++++- tests/basics/bytes.py | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/py/objstr.c b/py/objstr.c index ed9ab4e45b..13d957105a 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -223,7 +223,10 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size } if (MP_OBJ_IS_SMALL_INT(args[0])) { - uint len = MP_OBJ_SMALL_INT_VALUE(args[0]); + mp_int_t len = MP_OBJ_SMALL_INT_VALUE(args[0]); + if (len < 0) { + mp_raise_ValueError(NULL); + } vstr_t vstr; vstr_init_len(&vstr, len); memset(vstr.buf, 0, len); diff --git a/tests/basics/bytes.py b/tests/basics/bytes.py index 1d97e6b16f..0b6b14fa55 100644 --- a/tests/basics/bytes.py +++ b/tests/basics/bytes.py @@ -56,3 +56,9 @@ print(x[0], x[1], x[2], x[3]) print(bytes([128, 255])) # For sequence of unknown len print(bytes(iter([128, 255]))) + +# Shouldn't be able to make bytes with negative length +try: + bytes(-1) +except ValueError: + print('ValueError') From 27fa9881a9294c6a6875856c44101e5b33d27a3b Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 19 Feb 2018 17:02:56 +1100 Subject: [PATCH 332/828] esp32/modnetwork: Implement dhcp_hostname for WLAN.config(). --- ports/esp32/modnetwork.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index 3c348fc15b..ef817de52d 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -445,6 +445,11 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs cfg.ap.channel = mp_obj_get_int(kwargs->table[i].value); break; } + case QS(MP_QSTR_dhcp_hostname): { + const char *s = mp_obj_str_get_str(kwargs->table[i].value); + ESP_EXCEPTIONS(tcpip_adapter_set_hostname(self->if_id, s)); + break; + } default: goto unknown; } @@ -494,6 +499,12 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs req_if = WIFI_IF_AP; val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel); break; + case QS(MP_QSTR_dhcp_hostname): { + const char *s; + ESP_EXCEPTIONS(tcpip_adapter_get_hostname(self->if_id, &s)); + val = mp_obj_new_str(s, strlen(s)); + break; + } default: goto unknown; } From 6e7819ee2ee20ec9f09feb40b68be5973797f874 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 20 Feb 2018 17:56:58 +1100 Subject: [PATCH 333/828] py/objmodule: Factor common code for calling __init__ on builtin module. --- py/builtinimport.c | 14 +------------- py/objmodule.c | 28 +++++++++++++++++----------- py/objmodule.h | 9 +++++++++ 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/py/builtinimport.c b/py/builtinimport.c index 97c1789f84..19bc9fc954 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -389,19 +389,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { } // found weak linked module module_obj = el->value; - if (MICROPY_MODULE_BUILTIN_INIT) { - // look for __init__ and call it if it exists - // Note: this code doesn't work fully correctly because it allows the - // __init__ function to be called twice if the module is imported by its - // non-weak-link name. Also, this code is duplicated in objmodule.c. - mp_obj_t dest[2]; - mp_load_method_maybe(el->value, MP_QSTR___init__, dest); - if (dest[0] != MP_OBJ_NULL) { - mp_call_method_n_kw(0, 0, dest); - // register module so __init__ is not called again - mp_module_register(mod_name, el->value); - } - } + mp_module_call_init(mod_name, module_obj); } else { no_exist: #else diff --git a/py/objmodule.c b/py/objmodule.c index f9363e379b..c4aba3a7b4 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -247,17 +247,7 @@ mp_obj_t mp_module_get(qstr module_name) { if (el == NULL) { return MP_OBJ_NULL; } - - if (MICROPY_MODULE_BUILTIN_INIT) { - // look for __init__ and call it if it exists - mp_obj_t dest[2]; - mp_load_method_maybe(el->value, MP_QSTR___init__, dest); - if (dest[0] != MP_OBJ_NULL) { - mp_call_method_n_kw(0, 0, dest); - // register module so __init__ is not called again - mp_module_register(module_name, el->value); - } - } + mp_module_call_init(module_name, el->value); } // module found, return it @@ -268,3 +258,19 @@ void mp_module_register(qstr qst, mp_obj_t module) { mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map; mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module; } + +#if MICROPY_MODULE_BUILTIN_INIT +void mp_module_call_init(qstr module_name, mp_obj_t module_obj) { + // Look for __init__ and call it if it exists + mp_obj_t dest[2]; + mp_load_method_maybe(module_obj, MP_QSTR___init__, dest); + if (dest[0] != MP_OBJ_NULL) { + mp_call_method_n_kw(0, 0, dest); + // Register module so __init__ is not called again. + // If a module can be referenced by more than one name (eg due to weak links) + // then __init__ will still be called for each distinct import, and it's then + // up to the particular module to make sure it's __init__ code only runs once. + mp_module_register(module_name, module_obj); + } +} +#endif diff --git a/py/objmodule.h b/py/objmodule.h index b5c07dc333..b7702ec50b 100644 --- a/py/objmodule.h +++ b/py/objmodule.h @@ -34,4 +34,13 @@ extern const mp_map_t mp_builtin_module_weak_links_map; mp_obj_t mp_module_get(qstr module_name); void mp_module_register(qstr qstr, mp_obj_t module); +#if MICROPY_MODULE_BUILTIN_INIT +void mp_module_call_init(qstr module_name, mp_obj_t module_obj); +#else +static inline void mp_module_call_init(qstr module_name, mp_obj_t module_obj) { + (void)module_name; + (void)module_obj; +} +#endif + #endif // MICROPY_INCLUDED_PY_OBJMODULE_H From 209936880df4d63730ea77cf4b6f84e5f2f56d7c Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 20 Feb 2018 18:00:44 +1100 Subject: [PATCH 334/828] py/builtinimport: Add compile-time option to disable external imports. The new option is MICROPY_ENABLE_EXTERNAL_IMPORT and is enabled by default so that the default behaviour is the same as before. With it disabled import is only supported for built-in modules, not for external files nor frozen modules. This allows to support targets that have no filesystem of any kind and that only have access to pre-supplied built-in modules implemented natively. --- py/builtinimport.c | 39 +++++++++++++++++++++++++++++++++++++++ py/mpconfig.h | 7 +++++++ py/runtime.c | 9 +++++++++ 3 files changed, 55 insertions(+) diff --git a/py/builtinimport.c b/py/builtinimport.c index 19bc9fc954..b8ed096caf 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -44,6 +44,8 @@ #define DEBUG_printf(...) (void)0 #endif +#if MICROPY_ENABLE_EXTERNAL_IMPORT + #define PATH_SEP_CHAR '/' bool mp_obj_is_package(mp_obj_t module) { @@ -473,4 +475,41 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { // Otherwise, we need to return top-level package return top_module_obj; } + +#else // MICROPY_ENABLE_EXTERNAL_IMPORT + +mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { + // Check that it's not a relative import + if (n_args >= 5 && MP_OBJ_SMALL_INT_VALUE(args[4]) != 0) { + mp_raise_NotImplementedError("relative import"); + } + + // Check if module already exists, and return it if it does + qstr module_name_qstr = mp_obj_str_get_qstr(args[0]); + mp_obj_t module_obj = mp_module_get(module_name_qstr); + if (module_obj != MP_OBJ_NULL) { + return module_obj; + } + + #if MICROPY_MODULE_WEAK_LINKS + // Check if there is a weak link to this module + mp_map_elem_t *el = mp_map_lookup((mp_map_t*)&mp_builtin_module_weak_links_map, MP_OBJ_NEW_QSTR(module_name_qstr), MP_MAP_LOOKUP); + if (el != NULL) { + // Found weak-linked module + mp_module_call_init(module_name_qstr, el->value); + return el->value; + } + #endif + + // Couldn't find the module, so fail + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_msg(&mp_type_ImportError, "module not found"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, + "no module named '%q'", module_name_qstr)); + } +} + +#endif // MICROPY_ENABLE_EXTERNAL_IMPORT + MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin___import___obj, 1, 5, mp_builtin___import__); diff --git a/py/mpconfig.h b/py/mpconfig.h index b8a96f0b0a..e9071df2f7 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -405,6 +405,13 @@ /*****************************************************************************/ /* Python internal features */ +// Whether to enable import of external modules +// When disabled, only importing of built-in modules is supported +// When enabled, a port must implement mp_import_stat (among other things) +#ifndef MICROPY_ENABLE_EXTERNAL_IMPORT +#define MICROPY_ENABLE_EXTERNAL_IMPORT (1) +#endif + // Whether to use the POSIX reader for importing files #ifndef MICROPY_READER_POSIX #define MICROPY_READER_POSIX (0) diff --git a/py/runtime.c b/py/runtime.c index 9dff9847a0..65d0df639e 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1337,6 +1337,8 @@ import_error: return dest[0]; } + #if MICROPY_ENABLE_EXTERNAL_IMPORT + // See if it's a package, then can try FS import if (!mp_obj_is_package(module)) { goto import_error; @@ -1363,6 +1365,13 @@ import_error: // TODO lookup __import__ and call that instead of going straight to builtin implementation return mp_builtin___import__(5, args); + + #else + + // Package import not supported with external imports disabled + goto import_error; + + #endif } void mp_import_all(mp_obj_t module) { From 7e2a48858cec549879ae87384398008d82887766 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 20 Feb 2018 18:30:22 +1100 Subject: [PATCH 335/828] py/modmicropython: Allow to have stack_use() func without mem_info(). The micropython.stack_use() function is useful to query the current C stack usage, and it's inclusion in the micropython module doesn't need to be tied to the inclusion of mem_info()/qstr_info() because it doesn't rely on any of the code from these functions. So this patch introduces the config option MICROPY_PY_MICROPYTHON_STACK_USE which can be used to independently control the inclusion of stack_use(). By default it is enabled if MICROPY_PY_MICROPYTHON_MEM_INFO is enabled (thus not changing any of the existing ports). --- py/modmicropython.c | 10 +++++----- py/mpconfig.h | 5 +++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/py/modmicropython.c b/py/modmicropython.c index c14a0177de..5cc7bdbe29 100644 --- a/py/modmicropython.c +++ b/py/modmicropython.c @@ -103,15 +103,15 @@ STATIC mp_obj_t mp_micropython_qstr_info(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_qstr_info_obj, 0, 1, mp_micropython_qstr_info); -#if MICROPY_STACK_CHECK +#endif // MICROPY_PY_MICROPYTHON_MEM_INFO + +#if MICROPY_PY_MICROPYTHON_STACK_USE STATIC mp_obj_t mp_micropython_stack_use(void) { return MP_OBJ_NEW_SMALL_INT(mp_stack_usage()); } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_stack_use_obj, mp_micropython_stack_use); #endif -#endif // MICROPY_PY_MICROPYTHON_MEM_INFO - #if MICROPY_ENABLE_PYSTACK STATIC mp_obj_t mp_micropython_pystack_use(void) { return MP_OBJ_NEW_SMALL_INT(mp_pystack_usage()); @@ -167,10 +167,10 @@ STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = { #endif { MP_ROM_QSTR(MP_QSTR_mem_info), MP_ROM_PTR(&mp_micropython_mem_info_obj) }, { MP_ROM_QSTR(MP_QSTR_qstr_info), MP_ROM_PTR(&mp_micropython_qstr_info_obj) }, - #if MICROPY_STACK_CHECK +#endif + #if MICROPY_PY_MICROPYTHON_STACK_USE { MP_ROM_QSTR(MP_QSTR_stack_use), MP_ROM_PTR(&mp_micropython_stack_use_obj) }, #endif -#endif #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0) { MP_ROM_QSTR(MP_QSTR_alloc_emergency_exception_buf), MP_ROM_PTR(&mp_alloc_emergency_exception_buf_obj) }, #endif diff --git a/py/mpconfig.h b/py/mpconfig.h index e9071df2f7..d38536f971 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -907,6 +907,11 @@ typedef double mp_float_t; #define MICROPY_PY_MICROPYTHON_MEM_INFO (0) #endif +// Whether to provide "micropython.stack_use" function +#ifndef MICROPY_PY_MICROPYTHON_STACK_USE +#define MICROPY_PY_MICROPYTHON_STACK_USE (MICROPY_PY_MICROPYTHON_MEM_INFO) +#endif + // Whether to provide "array" module. Note that large chunk of the // underlying code is shared with "bytearray" builtin type, so to // get real savings, it should be disabled too. From 8769049e935a89daa51883755457a083a5589d4e Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 20 Feb 2018 19:19:02 +1100 Subject: [PATCH 336/828] py/objstr: Remove unnecessary check for positive splits variable. At this point in the code the variable "splits" is guaranteed to be positive due to the check for "splits == 0" above it. --- py/objstr.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/py/objstr.c b/py/objstr.c index 13d957105a..c42f38e75b 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -663,9 +663,7 @@ STATIC mp_obj_t str_rsplit(size_t n_args, const mp_obj_t *args) { } res->items[idx--] = mp_obj_new_str_of_type(self_type, s + sep_len, last - s - sep_len); last = s; - if (splits > 0) { - splits--; - } + splits--; } if (idx != 0) { // We split less parts than split limit, now go cleanup surplus From fe3e17b026595f3386114e784b26a4a07810055c Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 21 Feb 2018 00:20:46 +1100 Subject: [PATCH 337/828] py/objint: Use MP_OBJ_IS_STR_OR_BYTES macro instead of 2 separate ones. --- py/objint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/objint.c b/py/objint.c index 4f2e610a50..59c58f2a61 100644 --- a/py/objint.c +++ b/py/objint.c @@ -378,7 +378,7 @@ mp_obj_t mp_obj_int_binary_op_extra_cases(mp_binary_op_t op, mp_obj_t lhs_in, mp // true acts as 0 return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(1)); } else if (op == MP_BINARY_OP_MULTIPLY) { - if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_bytes) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) { + if (MP_OBJ_IS_STR_OR_BYTES(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) { // multiply is commutative for these types, so delegate to them return mp_binary_op(op, rhs_in, lhs_in); } From c49a73ab0e18035edaa732d31c882a13534caa7a Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 20 Feb 2018 16:45:04 +1100 Subject: [PATCH 338/828] esp32: Update to the latest ESP IDF. This update requires a new ESP32 toolchain: 1.22.0-80-g6c4433a-5.2.0. --- ports/esp32/Makefile | 15 +++++++++++---- ports/esp32/esp32.custom_common.ld | 8 +++++++- ports/esp32/machine_wdt.c | 4 ++-- ports/esp32/main.c | 2 +- ports/esp32/sdkconfig.h | 8 ++++++++ 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 02aebc1a63..eb0a3be249 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -21,7 +21,7 @@ FLASH_FREQ ?= 40m FLASH_SIZE ?= 4MB CROSS_COMPILE ?= xtensa-esp32-elf- -ESPIDF_SUPHASH := 2c95a77cf93781f296883d5dbafcdc18e4389656 +ESPIDF_SUPHASH := 3ede9f011b50999b0560683f9419538c066dd09e # paths to ESP IDF and its components ifeq ($(ESPIDF),) @@ -90,6 +90,7 @@ INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/include INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/port/include INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include INC_ESPCOMP += -I$(ESPCOMP)/app_trace/include +INC_ESPCOMP += -I$(ESPCOMP)/app_update/include CFLAGS_BASE = -std=gnu99 -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -mlongcalls -nostdlib -Wall -Werror -Wno-error=unused-function -Wno-error=unused-but-set-variable -Wno-error=unused-variable -Wno-error=deprecated-declarations -DMBEDTLS_CONFIG_FILE='"mbedtls/esp_config.h"' -DHAVE_CONFIG_H -DESP_PLATFORM CFLAGS = $(CFLAGS_BASE) $(INC) $(INC_ESPCOMP) @@ -336,9 +337,9 @@ ESPIDF_VFS_O = $(addprefix $(ESPCOMP)/vfs/,\ vfs.o \ ) -ESPIDF_JSON_O = $(addprefix $(ESPCOMP)/json/,\ - library/cJSON.o \ - port/cJSON_Utils.o \ +ESPIDF_JSON_O = $(addprefix $(ESPCOMP)/json/cJSON/,\ + cJSON.o \ + cJSON_Utils.o \ ) ESPIDF_LOG_O = $(addprefix $(ESPCOMP)/log/,\ @@ -358,6 +359,10 @@ ESPIDF_APP_TRACE_O = $(addprefix $(ESPCOMP)/app_trace/,\ app_trace.o \ ) +ESPIDF_APP_UPDATE_O = $(addprefix $(ESPCOMP)/app_update/,\ + esp_ota_ops.o \ + ) + ESPIDF_NEWLIB_O = $(addprefix $(ESPCOMP)/newlib/,\ time.o \ syscalls.o \ @@ -594,6 +599,7 @@ OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_MBEDTLS_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_XTENSA_DEBUG_MODULE_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_TCPIP_ADAPTER_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_APP_TRACE_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_APP_UPDATE_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NGHTTP_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NVS_FLASH_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_OPENSSL_O)) @@ -671,6 +677,7 @@ $(BUILD)/%.o: %.cpp $(BUILD)/bootloader/$(ESPCOMP)/%.o: CFLAGS += -DBOOTLOADER_BUILD=1 -I$(ESPCOMP)/bootloader_support/include_priv -I$(ESPCOMP)/bootloader_support/include -I$(ESPCOMP)/micro-ecc/micro-ecc -I$(ESPCOMP)/esp32 -Wno-error=format BOOTLOADER_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ + bootloader_support/src/bootloader_clock.o \ bootloader_support/src/bootloader_flash.o \ bootloader_support/src/bootloader_random.o \ bootloader_support/src/bootloader_sha.o \ diff --git a/ports/esp32/esp32.custom_common.ld b/ports/esp32/esp32.custom_common.ld index eb1dee3c0f..c9a61f0184 100644 --- a/ports/esp32/esp32.custom_common.ld +++ b/ports/esp32/esp32.custom_common.ld @@ -89,7 +89,6 @@ SECTIONS *esp32/core_dump.o(.literal .text .literal.* .text.*) *app_trace/*(.literal .text .literal.* .text.*) *xtensa-debug-module/eri.o(.literal .text .literal.* .text.*) - *libphy.a:(.literal .text .literal.* .text.*) *librtc.a:(.literal .text .literal.* .text.*) *libsoc.a:(.literal .text .literal.* .text.*) *libhal.a:(.literal .text .literal.* .text.*) @@ -196,6 +195,13 @@ SECTIONS *(.gnu.linkonce.lit4.*) _lit4_end = ABSOLUTE(.); . = ALIGN(4); + _thread_local_start = ABSOLUTE(.); + *(.tdata) + *(.tdata.*) + *(.tbss) + *(.tbss.*) + _thread_local_end = ABSOLUTE(.); + . = ALIGN(4); } >drom0_0_seg .flash.text : diff --git a/ports/esp32/machine_wdt.c b/ports/esp32/machine_wdt.c index 0389e86896..f0436056f6 100644 --- a/ports/esp32/machine_wdt.c +++ b/ports/esp32/machine_wdt.c @@ -51,7 +51,7 @@ STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type_in, size_t n_args switch (id) { case 0: - esp_task_wdt_feed(); + esp_task_wdt_add(NULL); return &wdt_default; default: mp_raise_ValueError(NULL); @@ -60,7 +60,7 @@ STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type_in, size_t n_args STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) { (void)self_in; - esp_task_wdt_feed(); + esp_task_wdt_reset(); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed); diff --git a/ports/esp32/main.c b/ports/esp32/main.c index 091cbddc98..5b1be4cf74 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -53,7 +53,7 @@ #define MP_TASK_PRIORITY (ESP_TASK_PRIO_MIN + 1) #define MP_TASK_STACK_SIZE (16 * 1024) #define MP_TASK_STACK_LEN (MP_TASK_STACK_SIZE / sizeof(StackType_t)) -#define MP_TASK_HEAP_SIZE (96 * 1024) +#define MP_TASK_HEAP_SIZE (92 * 1024) STATIC StaticTask_t mp_task_tcb; STATIC StackType_t mp_task_stack[MP_TASK_STACK_LEN] __attribute__((aligned (8))); diff --git a/ports/esp32/sdkconfig.h b/ports/esp32/sdkconfig.h index 3f5c7402a5..113c0395fa 100644 --- a/ports/esp32/sdkconfig.h +++ b/ports/esp32/sdkconfig.h @@ -1,3 +1,8 @@ +/* Start bootloader config */ +#define CONFIG_FLASHMODE_DIO 1 +#define CONFIG_ESPTOOLPY_FLASHFREQ_40M 1 +/* End bootloader config */ + #define CONFIG_TRACEMEM_RESERVE_DRAM 0x0 #define CONFIG_BT_RESERVE_DRAM 0x0 #define CONFIG_ULP_COPROC_RESERVE_MEM 0 @@ -104,6 +109,9 @@ #define CONFIG_LWIP_THREAD_LOCAL_STORAGE_INDEX 0 #define CONFIG_LWIP_DHCP_DOES_ARP_CHECK 1 #define CONFIG_LWIP_DHCP_MAX_NTP_SERVERS 1 +#define CONFIG_LWIP_DHCPS_LEASE_UNIT 60 +#define CONFIG_LWIP_DHCPS_MAX_STATION_NUM 8 +#define CONFIG_LWIP_MAX_ACTIVE_TCP 16 #define CONFIG_LWIP_MAX_SOCKETS 8 #define CONFIG_LWIP_SO_REUSE 1 #define CONFIG_LWIP_ETHARP_TRUST_IP_MAC 1 From e600810f39cf99ebab825fdd96b3c875dea4d6d5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 21 Feb 2018 14:22:33 +1100 Subject: [PATCH 339/828] esp32/main: Allocate the uPy heap via malloc instead of on the bss. This allows to get slightly more memory for the heap (currently around 110k vs previous 92k) because the ESP IDF frees up some RAM after booting up. --- ports/esp32/main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ports/esp32/main.c b/ports/esp32/main.c index 5b1be4cf74..eebf183cd6 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -53,11 +53,9 @@ #define MP_TASK_PRIORITY (ESP_TASK_PRIO_MIN + 1) #define MP_TASK_STACK_SIZE (16 * 1024) #define MP_TASK_STACK_LEN (MP_TASK_STACK_SIZE / sizeof(StackType_t)) -#define MP_TASK_HEAP_SIZE (92 * 1024) STATIC StaticTask_t mp_task_tcb; STATIC StackType_t mp_task_stack[MP_TASK_STACK_LEN] __attribute__((aligned (8))); -STATIC uint8_t mp_task_heap[MP_TASK_HEAP_SIZE]; void mp_task(void *pvParameter) { volatile uint32_t sp = (uint32_t)get_sp(); @@ -66,11 +64,15 @@ void mp_task(void *pvParameter) { #endif uart_init(); + // Allocate the uPy heap using malloc and get the largest available region + size_t mp_task_heap_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); + void *mp_task_heap = malloc(mp_task_heap_size); + soft_reset: // initialise the stack pointer for the main thread mp_stack_set_top((void *)sp); mp_stack_set_limit(MP_TASK_STACK_SIZE - 1024); - gc_init(mp_task_heap, mp_task_heap + sizeof(mp_task_heap)); + gc_init(mp_task_heap, mp_task_heap + mp_task_heap_size); mp_init(); mp_obj_list_init(mp_sys_path, 0); mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); From cced43feb8ffee0791f82c0358265329347f88c7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 21 Feb 2018 19:09:38 +1100 Subject: [PATCH 340/828] esp32/modsocket: Allow getaddrinfo() to take up to 6 args. Currently only the first 2 args are used, but this patch should at least make getaddrinfo() signature-compatible with CPython and other bare-metal ports that use the lwip bindings. --- ports/esp32/modsocket.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index cba34d76c7..31d153964c 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -520,9 +520,11 @@ STATIC mp_obj_t get_socket(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_socket_obj, 0, 3, get_socket); -STATIC mp_obj_t esp_socket_getaddrinfo(const mp_obj_t host, const mp_obj_t port) { +STATIC mp_obj_t esp_socket_getaddrinfo(size_t n_args, const mp_obj_t *args) { + // TODO support additional args beyond the first two + struct addrinfo *res = NULL; - _socket_getaddrinfo2(host, port, &res); + _socket_getaddrinfo2(args[0], args[1], &res); mp_obj_t ret_list = mp_obj_new_list(0, NULL); for (struct addrinfo *resi = res; resi; resi = resi->ai_next) { @@ -552,7 +554,7 @@ STATIC mp_obj_t esp_socket_getaddrinfo(const mp_obj_t host, const mp_obj_t port) if (res) lwip_freeaddrinfo(res); return ret_list; } -STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_socket_getaddrinfo_obj, esp_socket_getaddrinfo); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_socket_getaddrinfo_obj, 2, 6, esp_socket_getaddrinfo); STATIC mp_obj_t esp_socket_initialize() { static int initialized = 0; From 970eedce8f37af46cb2b67fa0e91d76c82057541 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 6 Feb 2018 00:06:42 +0200 Subject: [PATCH 341/828] py/objdeque: Implement ucollections.deque type with fixed size. So far, implements just append() and popleft() methods, required for a normal queue. Constructor doesn't accept an arbitarry sequence to initialize from (am empty deque is always created), so an empty tuple must be passed as such. Only fixed-size deques are supported, so 2nd argument (size) is required. There's also an extension to CPython - if True is passed as 3rd argument, append(), instead of silently overwriting the oldest item on queue overflow, will throw IndexError. This behavior is desired in many cases, where queues should store information reliably, instead of silently losing some items. --- py/modcollections.c | 3 + py/mpconfig.h | 5 ++ py/obj.h | 1 + py/objdeque.c | 159 ++++++++++++++++++++++++++++++++++++++++++++ py/py.mk | 1 + 5 files changed, 169 insertions(+) create mode 100644 py/objdeque.c diff --git a/py/modcollections.c b/py/modcollections.c index 1a1560387a..bb6488471c 100644 --- a/py/modcollections.c +++ b/py/modcollections.c @@ -30,6 +30,9 @@ STATIC const mp_rom_map_elem_t mp_module_collections_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ucollections) }, + #if MICROPY_PY_COLLECTIONS_DEQUE + { MP_ROM_QSTR(MP_QSTR_deque), MP_ROM_PTR(&mp_type_deque) }, + #endif { MP_ROM_QSTR(MP_QSTR_namedtuple), MP_ROM_PTR(&mp_namedtuple_obj) }, #if MICROPY_PY_COLLECTIONS_ORDEREDDICT { MP_ROM_QSTR(MP_QSTR_OrderedDict), MP_ROM_PTR(&mp_type_ordereddict) }, diff --git a/py/mpconfig.h b/py/mpconfig.h index d38536f971..532b54ab0b 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -936,6 +936,11 @@ typedef double mp_float_t; #define MICROPY_PY_COLLECTIONS (1) #endif +// Whether to provide "ucollections.deque" type +#ifndef MICROPY_PY_COLLECTIONS_DEQUE +#define MICROPY_PY_COLLECTIONS_DEQUE (0) +#endif + // Whether to provide "collections.OrderedDict" type #ifndef MICROPY_PY_COLLECTIONS_ORDEREDDICT #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (0) diff --git a/py/obj.h b/py/obj.h index 2e715253c5..32b4301545 100644 --- a/py/obj.h +++ b/py/obj.h @@ -553,6 +553,7 @@ extern const mp_obj_type_t mp_type_list; extern const mp_obj_type_t mp_type_map; // map (the python builtin, not the dict implementation detail) extern const mp_obj_type_t mp_type_enumerate; extern const mp_obj_type_t mp_type_filter; +extern const mp_obj_type_t mp_type_deque; extern const mp_obj_type_t mp_type_dict; extern const mp_obj_type_t mp_type_ordereddict; extern const mp_obj_type_t mp_type_range; diff --git a/py/objdeque.c b/py/objdeque.c new file mode 100644 index 0000000000..15936f9ab9 --- /dev/null +++ b/py/objdeque.c @@ -0,0 +1,159 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/mpconfig.h" +#if MICROPY_PY_COLLECTIONS_DEQUE + +#include "py/runtime.h" + +typedef struct _mp_obj_deque_t { + mp_obj_base_t base; + size_t alloc; + size_t i_get; + size_t i_put; + mp_obj_t *items; + uint32_t flags; + #define FLAG_CHECK_OVERFLOW 1 +} mp_obj_deque_t; + +STATIC mp_obj_t deque_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 2, 3, false); + + /* Initialization from existing sequence is not supported, so an empty + tuple must be passed as such. */ + if (args[0] != mp_const_empty_tuple) { + mp_raise_ValueError(NULL); + } + + mp_obj_deque_t *o = m_new_obj(mp_obj_deque_t); + o->base.type = type; + o->alloc = mp_obj_get_int(args[1]) + 1; + o->i_get = o->i_put = 0; + o->items = m_new(mp_obj_t, o->alloc); + mp_seq_clear(o->items, 0, o->alloc, sizeof(*o->items)); + + if (n_args > 2) { + o->flags = mp_obj_get_int(args[2]); + } + + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t deque_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + switch (op) { + case MP_UNARY_OP_BOOL: + return mp_obj_new_bool(self->i_get != self->i_put); + case MP_UNARY_OP_LEN: { + mp_int_t len = self->i_put - self->i_get; + if (len < 0) { + len += self->alloc; + } + return MP_OBJ_NEW_SMALL_INT(len); + } + #if MICROPY_PY_SYS_GETSIZEOF + case MP_UNARY_OP_SIZEOF: { + size_t sz = sizeof(*self) + sizeof(mp_obj_t) * self->alloc; + return MP_OBJ_NEW_SMALL_INT(sz); + } + #endif + default: + return MP_OBJ_NULL; // op not supported + } +} + +STATIC mp_obj_t mp_obj_deque_append(mp_obj_t self_in, mp_obj_t arg) { + mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + + size_t new_i_put = self->i_put + 1; + if (new_i_put == self->alloc) { + new_i_put = 0; + } + + if (self->flags & FLAG_CHECK_OVERFLOW && new_i_put == self->i_get) { + mp_raise_msg(&mp_type_IndexError, "full"); + } + + self->items[self->i_put] = arg; + self->i_put = new_i_put; + + if (self->i_get == new_i_put) { + if (++self->i_get == self->alloc) { + self->i_get = 0; + } + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(deque_append_obj, mp_obj_deque_append); + +STATIC mp_obj_t deque_popleft(mp_obj_t self_in) { + mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->i_get == self->i_put) { + mp_raise_msg(&mp_type_IndexError, "empty"); + } + + mp_obj_t ret = self->items[self->i_get]; + self->items[self->i_get] = MP_OBJ_NULL; + + if (++self->i_get == self->alloc) { + self->i_get = 0; + } + + return ret; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(deque_popleft_obj, deque_popleft); + +STATIC mp_obj_t deque_clear(mp_obj_t self_in) { + mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + self->i_get = self->i_put = 0; + mp_seq_clear(self->items, 0, self->alloc, sizeof(*self->items)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(deque_clear_obj, deque_clear); + +STATIC const mp_rom_map_elem_t deque_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&deque_append_obj) }, + #if 0 + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&deque_clear_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_popleft), MP_ROM_PTR(&deque_popleft_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(deque_locals_dict, deque_locals_dict_table); + +const mp_obj_type_t mp_type_deque = { + { &mp_type_type }, + .name = MP_QSTR_deque, + .make_new = deque_make_new, + .unary_op = deque_unary_op, + .locals_dict = (mp_obj_dict_t*)&deque_locals_dict, +}; + +#endif // MICROPY_PY_COLLECTIONS_DEQUE diff --git a/py/py.mk b/py/py.mk index de82a971bc..6cfe21ca9e 100644 --- a/py/py.mk +++ b/py/py.mk @@ -158,6 +158,7 @@ PY_O_BASENAME = \ objcell.o \ objclosure.o \ objcomplex.o \ + objdeque.o \ objdict.o \ objenumerate.o \ objexcept.o \ From 6c3faf6c17521940eb3ec48a8af3d28b513e2ba2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 21 Feb 2018 22:52:58 +1100 Subject: [PATCH 342/828] py/objdeque: Allow to compile without warnings by disabling deque_clear. --- py/objdeque.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/py/objdeque.c b/py/objdeque.c index 15936f9ab9..a4c42c31fc 100644 --- a/py/objdeque.c +++ b/py/objdeque.c @@ -130,6 +130,7 @@ STATIC mp_obj_t deque_popleft(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(deque_popleft_obj, deque_popleft); +#if 0 STATIC mp_obj_t deque_clear(mp_obj_t self_in) { mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); self->i_get = self->i_put = 0; @@ -137,6 +138,7 @@ STATIC mp_obj_t deque_clear(mp_obj_t self_in) { return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(deque_clear_obj, deque_clear); +#endif STATIC const mp_rom_map_elem_t deque_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&deque_append_obj) }, From 82828340a0e8dfd946bafac01d38e59ff63ebe3b Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 21 Feb 2018 22:55:13 +1100 Subject: [PATCH 343/828] ports: Enable ucollections.deque on relevant ports. These ports are all capable of running uasyncio. --- ports/esp32/mpconfigport.h | 1 + ports/esp8266/mpconfigport.h | 1 + ports/stm32/mpconfigport.h | 1 + ports/unix/mpconfigport.h | 1 + ports/windows/mpconfigport.h | 1 + 5 files changed, 5 insertions(+) diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index e5fc2b4c5d..bf027f1c5c 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -90,6 +90,7 @@ #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) #define MICROPY_PY_ATTRTUPLE (1) #define MICROPY_PY_COLLECTIONS (1) +#define MICROPY_PY_COLLECTIONS_DEQUE (1) #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) #define MICROPY_PY_MATH (1) #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index c45ed92c73..fc992a4b1b 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -49,6 +49,7 @@ #define MICROPY_PY_ARRAY (1) #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) #define MICROPY_PY_COLLECTIONS (1) +#define MICROPY_PY_COLLECTIONS_DEQUE (1) #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) #define MICROPY_PY_MATH (1) #define MICROPY_PY_CMATH (0) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 0ade01d158..5b78d44450 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -97,6 +97,7 @@ #define MICROPY_PY_BUILTINS_HELP_MODULES (1) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) +#define MICROPY_PY_COLLECTIONS_DEQUE (1) #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) #define MICROPY_PY_CMATH (1) diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index 353bfa3e4b..06dae9da83 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -97,6 +97,7 @@ #define MICROPY_PY_SYS_MAXSIZE (1) #define MICROPY_PY_SYS_STDFILES (1) #define MICROPY_PY_SYS_EXC_INFO (1) +#define MICROPY_PY_COLLECTIONS_DEQUE (1) #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) #ifndef MICROPY_PY_MATH_SPECIAL_FUNCTIONS #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) diff --git a/ports/windows/mpconfigport.h b/ports/windows/mpconfigport.h index 1ae20fb04d..9db6d31ce8 100644 --- a/ports/windows/mpconfigport.h +++ b/ports/windows/mpconfigport.h @@ -83,6 +83,7 @@ #define MICROPY_PY_SYS_MAXSIZE (1) #define MICROPY_PY_SYS_STDFILES (1) #define MICROPY_PY_SYS_EXC_INFO (1) +#define MICROPY_PY_COLLECTIONS_DEQUE (1) #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) #define MICROPY_PY_CMATH (1) From 4668ec801e59125aaac3aa6892420d251f00ab3f Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 6 Feb 2018 11:58:40 +0200 Subject: [PATCH 344/828] tests/basics/deque*: Tests for ucollections.deque. --- tests/basics/deque1.py | 47 +++++++++++++++++++++++++++ tests/basics/deque2.py | 66 ++++++++++++++++++++++++++++++++++++++ tests/basics/deque2.py.exp | 15 +++++++++ 3 files changed, 128 insertions(+) create mode 100644 tests/basics/deque1.py create mode 100644 tests/basics/deque2.py create mode 100644 tests/basics/deque2.py.exp diff --git a/tests/basics/deque1.py b/tests/basics/deque1.py new file mode 100644 index 0000000000..ee51516b5c --- /dev/null +++ b/tests/basics/deque1.py @@ -0,0 +1,47 @@ +try: + try: + from ucollections import deque + except ImportError: + from collections import deque +except ImportError: + print("SKIP") + raise SystemExit + + +d = deque((), 2) +print(len(d)) +print(bool(d)) + +try: + d.popleft() +except IndexError: + print("IndexError") + +print(d.append(1)) +print(len(d)) +print(bool(d)) +print(d.popleft()) +print(len(d)) + +d.append(2) +print(d.popleft()) + +d.append(3) +d.append(4) +print(len(d)) +print(d.popleft(), d.popleft()) +try: + d.popleft() +except IndexError: + print("IndexError") + +d.append(5) +d.append(6) +d.append(7) +print(len(d)) +print(d.popleft(), d.popleft()) +print(len(d)) +try: + d.popleft() +except IndexError: + print("IndexError") diff --git a/tests/basics/deque2.py b/tests/basics/deque2.py new file mode 100644 index 0000000000..22d370e943 --- /dev/null +++ b/tests/basics/deque2.py @@ -0,0 +1,66 @@ +# Tests for deques with "check overflow" flag and other extensions +# wrt to CPython. +try: + try: + from ucollections import deque + except ImportError: + from collections import deque +except ImportError: + print("SKIP") + raise SystemExit + + +# Initial sequence is not supported +try: + deque([1, 2, 3], 10) +except ValueError: + print("ValueError") + +# Not even empty list, only empty tuple +try: + deque([], 10) +except ValueError: + print("ValueError") + +# Only fixed-size deques are supported, so length arg is mandatory +try: + deque(()) +except TypeError: + print("TypeError") + +d = deque((), 2, True) + +try: + d.popleft() +except IndexError: + print("IndexError") + +print(d.append(1)) +print(d.popleft()) + +d.append(2) +print(d.popleft()) + +d.append(3) +d.append(4) +print(d.popleft(), d.popleft()) +try: + d.popleft() +except IndexError as e: + print(repr(e)) + +d.append(5) +d.append(6) +print(len(d)) +try: + d.append(7) +except IndexError as e: + print(repr(e)) +print(len(d)) + +print(d.popleft(), d.popleft()) +print(len(d)) +try: + d.popleft() +except IndexError as e: + print(repr(e)) diff --git a/tests/basics/deque2.py.exp b/tests/basics/deque2.py.exp new file mode 100644 index 0000000000..3df8acf405 --- /dev/null +++ b/tests/basics/deque2.py.exp @@ -0,0 +1,15 @@ +ValueError +ValueError +TypeError +IndexError +None +1 +2 +3 4 +IndexError('empty',) +2 +IndexError('full',) +2 +5 6 +0 +IndexError('empty',) From 8f9b113be25bec821254027e3e3d634f20553226 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 21 Feb 2018 23:19:06 +1100 Subject: [PATCH 345/828] tests/basics: Add tests to improve coverage of py/objdeque.c. --- tests/basics/deque1.py | 15 +++++++++++++++ tests/basics/sys_getsizeof.py | 7 +++++++ 2 files changed, 22 insertions(+) diff --git a/tests/basics/deque1.py b/tests/basics/deque1.py index ee51516b5c..6b5669c45e 100644 --- a/tests/basics/deque1.py +++ b/tests/basics/deque1.py @@ -45,3 +45,18 @@ try: d.popleft() except IndexError: print("IndexError") + +# Case where get index wraps around when appending to full deque +d = deque((), 2) +d.append(1) +d.append(2) +d.append(3) +d.append(4) +d.append(5) +print(d.popleft(), d.popleft()) + +# Unsupported unary op +try: + ~d +except TypeError: + print("TypeError") diff --git a/tests/basics/sys_getsizeof.py b/tests/basics/sys_getsizeof.py index d16eb1561a..fe1b403e04 100644 --- a/tests/basics/sys_getsizeof.py +++ b/tests/basics/sys_getsizeof.py @@ -13,3 +13,10 @@ print(sys.getsizeof({1: 2}) >= 2) class A: pass print(sys.getsizeof(A()) > 0) + +# Only test deque if we have it +try: + from ucollections import deque + assert sys.getsizeof(deque((), 1)) > 0 +except ImportError: + pass From 160d6708684de8c71895f90bc699a5879fb6ed29 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 21 Feb 2018 23:34:17 +1100 Subject: [PATCH 346/828] py/objdeque: Protect against negative maxlen in deque constructor. Otherwise passing -1 as maxlen will lead to a zero allocation and subsequent unbound buffer overflow in deque.append() because i_put is allowed to grow without bound. --- py/objdeque.c | 8 +++++++- tests/basics/deque1.py | 6 ++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/py/objdeque.c b/py/objdeque.c index a4c42c31fc..573a48baf6 100644 --- a/py/objdeque.c +++ b/py/objdeque.c @@ -50,9 +50,15 @@ STATIC mp_obj_t deque_make_new(const mp_obj_type_t *type, size_t n_args, size_t mp_raise_ValueError(NULL); } + // Protect against -1 leading to zero-length allocation and bad array access + mp_int_t maxlen = mp_obj_get_int(args[1]); + if (maxlen < 0) { + mp_raise_ValueError(NULL); + } + mp_obj_deque_t *o = m_new_obj(mp_obj_deque_t); o->base.type = type; - o->alloc = mp_obj_get_int(args[1]) + 1; + o->alloc = maxlen + 1; o->i_get = o->i_put = 0; o->items = m_new(mp_obj_t, o->alloc); mp_seq_clear(o->items, 0, o->alloc, sizeof(*o->items)); diff --git a/tests/basics/deque1.py b/tests/basics/deque1.py index 6b5669c45e..19966fcb07 100644 --- a/tests/basics/deque1.py +++ b/tests/basics/deque1.py @@ -55,6 +55,12 @@ d.append(4) d.append(5) print(d.popleft(), d.popleft()) +# Negative maxlen is not allowed +try: + deque((), -1) +except ValueError: + print("ValueError") + # Unsupported unary op try: ~d From 6e675c1baaf0de0d56a2345376d6b5600bfab3aa Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 21 Feb 2018 23:36:46 +1100 Subject: [PATCH 347/828] py/objdeque: Use m_new0 when allocating items to avoid need to clear. Saves a few bytes of code space, and is more efficient because with MICROPY_GC_CONSERVATIVE_CLEAR enabled by default all memory is already cleared when allocated. --- py/objdeque.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/py/objdeque.c b/py/objdeque.c index 573a48baf6..bbb078103b 100644 --- a/py/objdeque.c +++ b/py/objdeque.c @@ -60,8 +60,7 @@ STATIC mp_obj_t deque_make_new(const mp_obj_type_t *type, size_t n_args, size_t o->base.type = type; o->alloc = maxlen + 1; o->i_get = o->i_put = 0; - o->items = m_new(mp_obj_t, o->alloc); - mp_seq_clear(o->items, 0, o->alloc, sizeof(*o->items)); + o->items = m_new0(mp_obj_t, o->alloc); if (n_args > 2) { o->flags = mp_obj_get_int(args[2]); From 8ca469cae299f8e93dfe721bb915adb217dc4cfe Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 22 Feb 2018 11:13:04 +1100 Subject: [PATCH 348/828] py/py.mk: Split list of uPy sources into core and extmod files. If a port only needs the core files then it can now use the $(PY_CORE_O) variable instead of $(PY_O). $(PY_EXTMOD_O) contains the list of extmod files (including some files from lib/). $(PY_O) retains its original definition as the list of all object file (including those for frozen code) and is a convenience variable for ports that want everything. --- py/py.mk | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/py/py.mk b/py/py.mk index 6cfe21ca9e..20574d2c50 100644 --- a/py/py.mk +++ b/py/py.mk @@ -101,7 +101,7 @@ $(BUILD)/extmod/modbtree.o: CFLAGS += $(BTREE_DEFS) endif # py object files -PY_O_BASENAME = \ +PY_CORE_O_BASENAME = \ mpstate.o \ nlr.o \ nlrx86.o \ @@ -214,6 +214,8 @@ PY_O_BASENAME = \ repl.o \ smallint.o \ frozenmod.o \ + +PY_EXTMOD_O_BASENAME = \ ../extmod/moductypes.o \ ../extmod/modujson.o \ ../extmod/modure.o \ @@ -248,7 +250,11 @@ PY_O_BASENAME = \ ../lib/utils/printf.o \ # prepend the build destination prefix to the py object files -PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME)) +PY_CORE_O = $(addprefix $(PY_BUILD)/, $(PY_CORE_O_BASENAME)) +PY_EXTMOD_O = $(addprefix $(PY_BUILD)/, $(PY_EXTMOD_O_BASENAME)) + +# this is a convenience variable for ports that want core, extmod and frozen code +PY_O = $(PY_CORE_O) $(PY_EXTMOD_O) # object file for frozen files ifneq ($(FROZEN_DIR),) @@ -262,7 +268,7 @@ endif # Sources that may contain qstrings SRC_QSTR_IGNORE = nlr% emitnx86% emitnx64% emitnthumb% emitnarm% emitnxtensa% -SRC_QSTR = $(SRC_MOD) $(addprefix py/,$(filter-out $(SRC_QSTR_IGNORE),$(PY_O_BASENAME:.o=.c)) emitnative.c) +SRC_QSTR = $(SRC_MOD) $(addprefix py/,$(filter-out $(SRC_QSTR_IGNORE),$(PY_CORE_O_BASENAME:.o=.c)) emitnative.c $(PY_EXTMOD_O_BASENAME:.o=.c)) # Anything that depends on FORCE will be considered out-of-date FORCE: From 9df6451ec588e0e9bbd2e0f0eb2f177c01abd0f9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 22 Feb 2018 11:15:48 +1100 Subject: [PATCH 349/828] ports/{bare-arm,minimal}/Makefile: Only build with core source files. These ports don't need anything from extmod so don't include those files at all in the build. This speeds up the build by about 10% when building with a single core. --- ports/bare-arm/Makefile | 2 +- ports/minimal/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/bare-arm/Makefile b/ports/bare-arm/Makefile index 0fcd5d0272..a515db80e0 100644 --- a/ports/bare-arm/Makefile +++ b/ports/bare-arm/Makefile @@ -36,7 +36,7 @@ SRC_S = \ # startup_stm32f40xx.s \ gchelper.s \ -OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o)) +OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o)) all: $(BUILD)/firmware.elf diff --git a/ports/minimal/Makefile b/ports/minimal/Makefile index ae295d655e..e97fb16d8d 100644 --- a/ports/minimal/Makefile +++ b/ports/minimal/Makefile @@ -47,7 +47,7 @@ SRC_C = \ lib/mp-readline/readline.c \ $(BUILD)/_frozen_mpy.c \ -OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) ifeq ($(CROSS), 1) all: $(BUILD)/firmware.dfu From 65ef59a9b550bf89ae5b14130f0f8e6ff6d357ca Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 22 Feb 2018 11:32:31 +1100 Subject: [PATCH 350/828] py/py.mk: Remove .. path component from list of extmod files. This just makes it a bit cleaner in the output of the build process: instead of "CC ../../py/../extmod/" there is now "CC ../../extmod/". --- py/py.mk | 75 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/py/py.mk b/py/py.mk index 20574d2c50..879c63248b 100644 --- a/py/py.mk +++ b/py/py.mk @@ -101,7 +101,7 @@ $(BUILD)/extmod/modbtree.o: CFLAGS += $(BTREE_DEFS) endif # py object files -PY_CORE_O_BASENAME = \ +PY_CORE_O_BASENAME = $(addprefix py/,\ mpstate.o \ nlr.o \ nlrx86.o \ @@ -214,44 +214,45 @@ PY_CORE_O_BASENAME = \ repl.o \ smallint.o \ frozenmod.o \ + ) PY_EXTMOD_O_BASENAME = \ - ../extmod/moductypes.o \ - ../extmod/modujson.o \ - ../extmod/modure.o \ - ../extmod/moduzlib.o \ - ../extmod/moduheapq.o \ - ../extmod/modutimeq.o \ - ../extmod/moduhashlib.o \ - ../extmod/modubinascii.o \ - ../extmod/virtpin.o \ - ../extmod/machine_mem.o \ - ../extmod/machine_pinbase.o \ - ../extmod/machine_signal.o \ - ../extmod/machine_pulse.o \ - ../extmod/machine_i2c.o \ - ../extmod/machine_spi.o \ - ../extmod/modussl_axtls.o \ - ../extmod/modussl_mbedtls.o \ - ../extmod/modurandom.o \ - ../extmod/moduselect.o \ - ../extmod/modwebsocket.o \ - ../extmod/modwebrepl.o \ - ../extmod/modframebuf.o \ - ../extmod/vfs.o \ - ../extmod/vfs_reader.o \ - ../extmod/vfs_fat.o \ - ../extmod/vfs_fat_diskio.o \ - ../extmod/vfs_fat_file.o \ - ../extmod/vfs_fat_misc.o \ - ../extmod/utime_mphal.o \ - ../extmod/uos_dupterm.o \ - ../lib/embed/abort_.o \ - ../lib/utils/printf.o \ + extmod/moductypes.o \ + extmod/modujson.o \ + extmod/modure.o \ + extmod/moduzlib.o \ + extmod/moduheapq.o \ + extmod/modutimeq.o \ + extmod/moduhashlib.o \ + extmod/modubinascii.o \ + extmod/virtpin.o \ + extmod/machine_mem.o \ + extmod/machine_pinbase.o \ + extmod/machine_signal.o \ + extmod/machine_pulse.o \ + extmod/machine_i2c.o \ + extmod/machine_spi.o \ + extmod/modussl_axtls.o \ + extmod/modussl_mbedtls.o \ + extmod/modurandom.o \ + extmod/moduselect.o \ + extmod/modwebsocket.o \ + extmod/modwebrepl.o \ + extmod/modframebuf.o \ + extmod/vfs.o \ + extmod/vfs_reader.o \ + extmod/vfs_fat.o \ + extmod/vfs_fat_diskio.o \ + extmod/vfs_fat_file.o \ + extmod/vfs_fat_misc.o \ + extmod/utime_mphal.o \ + extmod/uos_dupterm.o \ + lib/embed/abort_.o \ + lib/utils/printf.o \ # prepend the build destination prefix to the py object files -PY_CORE_O = $(addprefix $(PY_BUILD)/, $(PY_CORE_O_BASENAME)) -PY_EXTMOD_O = $(addprefix $(PY_BUILD)/, $(PY_EXTMOD_O_BASENAME)) +PY_CORE_O = $(addprefix $(BUILD)/, $(PY_CORE_O_BASENAME)) +PY_EXTMOD_O = $(addprefix $(BUILD)/, $(PY_EXTMOD_O_BASENAME)) # this is a convenience variable for ports that want core, extmod and frozen code PY_O = $(PY_CORE_O) $(PY_EXTMOD_O) @@ -267,8 +268,8 @@ PY_O += $(BUILD)/$(BUILD)/frozen_mpy.o endif # Sources that may contain qstrings -SRC_QSTR_IGNORE = nlr% emitnx86% emitnx64% emitnthumb% emitnarm% emitnxtensa% -SRC_QSTR = $(SRC_MOD) $(addprefix py/,$(filter-out $(SRC_QSTR_IGNORE),$(PY_CORE_O_BASENAME:.o=.c)) emitnative.c $(PY_EXTMOD_O_BASENAME:.o=.c)) +SRC_QSTR_IGNORE = py/nlr% py/emitnx86% py/emitnx64% py/emitnthumb% py/emitnarm% py/emitnxtensa% +SRC_QSTR = $(SRC_MOD) $(filter-out $(SRC_QSTR_IGNORE),$(PY_CORE_O_BASENAME:.o=.c)) py/emitnative.c $(PY_EXTMOD_O_BASENAME:.o=.c) # Anything that depends on FORCE will be considered out-of-date FORCE: From 6af4515969045701a44fc282f72f68b7faaeb538 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 22 Feb 2018 11:35:53 +1100 Subject: [PATCH 351/828] py: Use "GEN" consistently for describing files generated in the build. --- py/makeversionhdr.py | 2 +- py/mkrules.mk | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/py/makeversionhdr.py b/py/makeversionhdr.py index 749160b4df..aedc292e4b 100644 --- a/py/makeversionhdr.py +++ b/py/makeversionhdr.py @@ -99,7 +99,7 @@ def make_version_header(filename): # Only write the file if we need to if write_file: - print("Generating %s" % filename) + print("GEN %s" % filename) with open(filename, 'w') as f: f.write(file_data) diff --git a/py/mkrules.mk b/py/mkrules.mk index 96f6e35a64..fa7138695d 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -97,7 +97,7 @@ $(HEADER_BUILD): ifneq ($(FROZEN_DIR),) $(BUILD)/frozen.c: $(wildcard $(FROZEN_DIR)/*) $(HEADER_BUILD) $(FROZEN_EXTRA_DEPS) - $(ECHO) "Generating $@" + $(ECHO) "GEN $@" $(Q)$(MAKE_FROZEN) $(FROZEN_DIR) > $@ endif @@ -118,7 +118,7 @@ $(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/%.py $(TOP)/mpy-cross/mpy-cross # to build frozen_mpy.c from all .mpy files $(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h - @$(ECHO) "Creating $@" + @$(ECHO) "GEN $@" $(Q)$(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@ endif From a36c700d9b3bacd3bfba0eef5bf9c9ba19a0e440 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 22 Feb 2018 13:19:09 +1100 Subject: [PATCH 352/828] minimal/Makefile: Explicitly include lib/utils/printf.c in build. The bare-metal port needs it and it's no longer included by default since the Makefile now uses $(PY_CORE_O). --- ports/minimal/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/minimal/Makefile b/ports/minimal/Makefile index e97fb16d8d..64ad3cc0b2 100644 --- a/ports/minimal/Makefile +++ b/ports/minimal/Makefile @@ -41,6 +41,7 @@ LIBS = SRC_C = \ main.c \ uart_core.c \ + lib/utils/printf.c \ lib/utils/stdout_helpers.c \ lib/utils/pyexec.c \ lib/libc/string0.c \ From 60b0982bb2d82b1c7b026a6f9e227e6dc837b005 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 22 Feb 2018 14:22:45 +1100 Subject: [PATCH 353/828] stm32: Add board config option to enable/disable the ADC. The new option is MICROPY_HW_ENABLE_ADC and is enabled by default. --- ports/stm32/adc.c | 4 ++++ ports/stm32/modpyb.c | 2 ++ ports/stm32/mpconfigboard_common.h | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index b8b4f4e56a..ffa16c2f93 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -35,6 +35,8 @@ #include "genhdr/pins.h" #include "timer.h" +#if MICROPY_HW_ENABLE_ADC + /// \moduleref pyb /// \class ADC - analog to digital conversion: read analog values on a pin /// @@ -683,3 +685,5 @@ const mp_obj_type_t pyb_adc_all_type = { .make_new = adc_all_make_new, .locals_dict = (mp_obj_dict_t*)&adc_all_locals_dict, }; + +#endif // MICROPY_HW_ENABLE_ADC diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c index 2192b5fcfd..c7f2844a4d 100644 --- a/ports/stm32/modpyb.c +++ b/ports/stm32/modpyb.c @@ -218,8 +218,10 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_CAN), MP_ROM_PTR(&pyb_can_type) }, #endif + #if MICROPY_HW_ENABLE_ADC { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) }, { MP_ROM_QSTR(MP_QSTR_ADCAll), MP_ROM_PTR(&pyb_adc_all_type) }, + #endif #if MICROPY_HW_ENABLE_DAC { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&pyb_dac_type) }, diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 32b69cc788..6465608f7b 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -40,6 +40,11 @@ #define MICROPY_HW_ENABLE_RNG (0) #endif +// Whether to enable the ADC peripheral, exposed as pyb.ADC and pyb.ADCAll +#ifndef MICROPY_HW_ENABLE_ADC +#define MICROPY_HW_ENABLE_ADC (1) +#endif + // Whether to enable the DAC peripheral, exposed as pyb.DAC #ifndef MICROPY_HW_ENABLE_DAC #define MICROPY_HW_ENABLE_DAC (0) From c2f4f36010c8636f837aa28028d9dd9a951959d5 Mon Sep 17 00:00:00 2001 From: talljosh Date: Thu, 22 Feb 2018 09:46:19 +1000 Subject: [PATCH 354/828] examples/embedding: Update broken paths to use correct $(MPTOP). Some ".." need to be changed to $(MPTOP), and in some places "ports/" needs to be inserted to get to the "ports/unix/" subdir. --- examples/embedding/Makefile.upylib | 32 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/examples/embedding/Makefile.upylib b/examples/embedding/Makefile.upylib index 469f1f76e5..6896354fde 100644 --- a/examples/embedding/Makefile.upylib +++ b/examples/embedding/Makefile.upylib @@ -13,7 +13,7 @@ include $(MPTOP)/py/py.mk INC += -I. INC += -I.. INC += -I$(MPTOP) -INC += -I$(MPTOP)/unix +INC += -I$(MPTOP)/ports/unix INC += -I$(BUILD) # compiler settings @@ -79,7 +79,7 @@ endif endif ifeq ($(MICROPY_USE_READLINE),1) -INC += -I../lib/mp-readline +INC += -I$(MPTOP)/lib/mp-readline CFLAGS_MOD += -DMICROPY_USE_READLINE=1 LIB_SRC_C_EXTRA += mp-readline/readline.c endif @@ -105,11 +105,11 @@ endif ifeq ($(MICROPY_PY_FFI),1) ifeq ($(MICROPY_STANDALONE),1) -LIBFFI_CFLAGS_MOD := -I$(shell ls -1d ../lib/libffi/build_dir/out/lib/libffi-*/include) +LIBFFI_CFLAGS_MOD := -I$(shell ls -1d $(MPTOP)/lib/libffi/build_dir/out/lib/libffi-*/include) ifeq ($(MICROPY_FORCE_32BIT),1) - LIBFFI_LDFLAGS_MOD = ../lib/libffi/build_dir/out/lib32/libffi.a + LIBFFI_LDFLAGS_MOD = $(MPTOP)/lib/libffi/build_dir/out/lib32/libffi.a else - LIBFFI_LDFLAGS_MOD = ../lib/libffi/build_dir/out/lib/libffi.a + LIBFFI_LDFLAGS_MOD = $(MPTOP)/lib/libffi/build_dir/out/lib/libffi.a endif else LIBFFI_CFLAGS_MOD := $(shell pkg-config --cflags libffi) @@ -128,7 +128,7 @@ endif MAIN_C = main.c # source files -SRC_C = $(addprefix $(MPTOP)/unix/,\ +SRC_C = $(addprefix $(MPTOP)/ports/unix/,\ $(MAIN_C) \ gccollect.c \ unix_mphal.c \ @@ -181,18 +181,18 @@ deplibs: libffi axtls # install-exec-recursive & install-data-am targets are used to avoid building # docs and depending on makeinfo libffi: - cd ../lib/libffi; git clean -d -x -f - cd ../lib/libffi; ./autogen.sh - mkdir -p ../lib/libffi/build_dir; cd ../lib/libffi/build_dir; \ + cd $(MPTOP)/lib/libffi; git clean -d -x -f + cd $(MPTOP)/lib/libffi; ./autogen.sh + mkdir -p $(MPTOP)/lib/libffi/build_dir; cd $(MPTOP)/lib/libffi/build_dir; \ ../configure $(CROSS_COMPILE_HOST) --prefix=$$PWD/out CC="$(CC)" CXX="$(CXX)" LD="$(LD)"; \ make install-exec-recursive; make -C include install-data-am -axtls: ../lib/axtls/README - cd ../lib/axtls; cp config/upyconfig config/.config - cd ../lib/axtls; make oldconfig -B - cd ../lib/axtls; make clean - cd ../lib/axtls; make all CC="$(CC)" LD="$(LD)" +axtls: $(MPTOP)/lib/axtls/README + cd $(MPTOP)/lib/axtls; cp config/upyconfig config/.config + cd $(MPTOP)/lib/axtls; make oldconfig -B + cd $(MPTOP)/lib/axtls; make clean + cd $(MPTOP)/lib/axtls; make all CC="$(CC)" LD="$(LD)" -../lib/axtls/README: +$(MPTOP)/lib/axtls/README: @echo "You cloned without --recursive, fetching submodules for you." - (cd ..; git submodule update --init --recursive) + (cd $(MPTOP); git submodule update --init --recursive) From 6b40a060574462bcf5e2f204a657cbac3a82d3c1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 23 Feb 2018 13:15:01 +1100 Subject: [PATCH 355/828] examples/embedding: Don't prefix $(MPTOP) to ports/unix source files. Otherwise the build process puts the corresponding output object files in two directories lower, not in build/ports/unix. --- examples/embedding/Makefile.upylib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/embedding/Makefile.upylib b/examples/embedding/Makefile.upylib index 6896354fde..6d6302050c 100644 --- a/examples/embedding/Makefile.upylib +++ b/examples/embedding/Makefile.upylib @@ -128,7 +128,7 @@ endif MAIN_C = main.c # source files -SRC_C = $(addprefix $(MPTOP)/ports/unix/,\ +SRC_C = $(addprefix ports/unix/,\ $(MAIN_C) \ gccollect.c \ unix_mphal.c \ From e6220618ce91557e9658e71139aaa7764604fba1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 23 Feb 2018 16:27:30 +1100 Subject: [PATCH 356/828] stm32: Use "GEN" for describing files generated in the build. Instead of "Create", to match the build output from the py/ core. --- ports/stm32/Makefile | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 1ef303cd4b..854820abe3 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -391,13 +391,13 @@ deploy-openocd: $(BUILD)/firmware.dfu $(Q)$(OPENOCD) -f $(OPENOCD_CONFIG) -c "stm_flash $(BUILD)/firmware0.bin $(FLASH_ADDR) $(BUILD)/firmware1.bin $(TEXT_ADDR)" $(BUILD)/firmware.dfu: $(BUILD)/firmware.elf - $(ECHO) "Create $@" + $(ECHO) "GEN $@" $(Q)$(OBJCOPY) -O binary -j .isr_vector $^ $(BUILD)/firmware0.bin $(Q)$(OBJCOPY) -O binary -j .text -j .data $^ $(BUILD)/firmware1.bin $(Q)$(PYTHON) $(DFU) -b $(FLASH_ADDR):$(BUILD)/firmware0.bin -b $(TEXT_ADDR):$(BUILD)/firmware1.bin $@ $(BUILD)/firmware.hex: $(BUILD)/firmware.elf - $(ECHO) "Create $@" + $(ECHO) "GEN $@" $(Q)$(OBJCOPY) -O ihex $< $@ $(BUILD)/firmware.elf: $(OBJ) @@ -446,7 +446,7 @@ main.c: $(GEN_CDCINF_HEADER) # Use a pattern rule here so that make will only call make-pins.py once to make # both pins_$(BOARD).c and pins.h $(BUILD)/%_$(BOARD).c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%_af_const.h $(BUILD)/%_qstr.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD) - $(ECHO) "Create $@" + $(ECHO) "GEN $@" $(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) --qstr $(GEN_PINS_QSTR) --af-const $(GEN_PINS_AF_CONST) --af-py $(GEN_PINS_AF_PY) > $(GEN_PINS_SRC) $(BUILD)/pins_$(BOARD).o: $(BUILD)/pins_$(BOARD).c @@ -461,22 +461,22 @@ CMSIS_MCU_HDR = $(CMSIS_DIR)/$(CMSIS_MCU_LOWER).h modmachine.c: $(GEN_PLLFREQTABLE_HDR) $(GEN_PLLFREQTABLE_HDR): $(PLLVALUES) | $(HEADER_BUILD) - $(ECHO) "Create $@" + $(ECHO) "GEN $@" $(Q)$(PYTHON) $(PLLVALUES) -c file:boards/$(BOARD)/stm32$(MCU_SERIES)xx_hal_conf.h > $@ $(BUILD)/modstm.o: $(GEN_STMCONST_HDR) # Use a pattern rule here so that make will only call make-stmconst.py once to # make both modstm_const.h and modstm_qstr.h $(HEADER_BUILD)/%_const.h $(BUILD)/%_qstr.h: $(CMSIS_MCU_HDR) make-stmconst.py | $(HEADER_BUILD) - $(ECHO) "Create stmconst $@" + $(ECHO) "GEN stmconst $@" $(Q)$(PYTHON) make-stmconst.py --qstr $(GEN_STMCONST_QSTR) --mpz $(GEN_STMCONST_MPZ) $(CMSIS_MCU_HDR) > $(GEN_STMCONST_HDR) $(GEN_CDCINF_HEADER): $(GEN_CDCINF_FILE) $(FILE2H) | $(HEADER_BUILD) - $(ECHO) "Create $@" + $(ECHO) "GEN $@" $(Q)$(PYTHON) $(FILE2H) $< > $@ $(GEN_CDCINF_FILE): $(CDCINF_TEMPLATE) $(INSERT_USB_IDS) $(USB_IDS_FILE) | $(HEADER_BUILD) - $(ECHO) "Create $@" + $(ECHO) "GEN $@" $(Q)$(PYTHON) $(INSERT_USB_IDS) $(USB_IDS_FILE) $< > $@ include $(TOP)/py/mkrules.mk From ea05b400df92a5d2282ca139f282b83db4740e22 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 23 Feb 2018 16:30:47 +1100 Subject: [PATCH 357/828] stm32/flash: Use FLASH_TYPEPROGRAM_WORD to support newer HALs. --- ports/stm32/flash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/flash.c b/ports/stm32/flash.c index bebb3a1619..10e1d2eff1 100644 --- a/ports/stm32/flash.c +++ b/ports/stm32/flash.c @@ -228,7 +228,7 @@ void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) // program the flash word by word for (int i = 0; i < num_word32; i++) { - if (HAL_FLASH_Program(TYPEPROGRAM_WORD, flash_dest, *src) != HAL_OK) { + if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, flash_dest, *src) != HAL_OK) { // error occurred during flash write HAL_FLASH_Lock(); // lock the flash return; From 989fc16162125c9c1c65e0f74d9d7bc73bc9a340 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 23 Feb 2018 16:54:07 +1100 Subject: [PATCH 358/828] stm32: Move MCU-specific cfg from mphalport.h to mpconfigboard_common.h. It's cleaner to have all the MCU-specific configuration in one location, not least to help with adding support for a new MCU series. --- ports/stm32/mpconfigboard_common.h | 53 ++++++++++++++++++++++++------ ports/stm32/mpconfigport.h | 2 -- ports/stm32/mphalport.h | 25 -------------- 3 files changed, 43 insertions(+), 37 deletions(-) diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 6465608f7b..7befe998af 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -27,6 +27,8 @@ // Common settings and defaults for board configuration. // The defaults here should be overridden in mpconfigboard.h. +#include STM32_HAL_H + /*****************************************************************************/ // Feature settings with defaults @@ -93,19 +95,37 @@ /*****************************************************************************/ // General configuration -// Define the maximum number of peripherals that the MCU supports -#if defined(MCU_SERIES_F7) -#define PYB_EXTI_NUM_VECTORS (24) -#define MICROPY_HW_MAX_TIMER (17) -#define MICROPY_HW_MAX_UART (8) -#elif defined(MCU_SERIES_L4) -#define PYB_EXTI_NUM_VECTORS (23) -#define MICROPY_HW_MAX_TIMER (17) -#define MICROPY_HW_MAX_UART (6) -#else +// Configuration for STM32F4 series +#if defined(STM32F4) + +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7a10) #define PYB_EXTI_NUM_VECTORS (23) #define MICROPY_HW_MAX_TIMER (14) #define MICROPY_HW_MAX_UART (6) + +// Configuration for STM32F7 series +#elif defined(STM32F7) + +#if defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F732xx) || defined(STM32F733xx) +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff07a10) +#else +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff0f420) +#endif + +#define PYB_EXTI_NUM_VECTORS (24) +#define MICROPY_HW_MAX_TIMER (17) +#define MICROPY_HW_MAX_UART (8) + +// Configuration for STM32L4 series +#elif defined(STM32L4) + +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7590) +#define PYB_EXTI_NUM_VECTORS (23) +#define MICROPY_HW_MAX_TIMER (17) +#define MICROPY_HW_MAX_UART (6) + +#else +#error Unsupported MCU series #endif // Enable hardware I2C if there are any peripherals defined @@ -118,3 +138,16 @@ // Pin definition header file #define MICROPY_PIN_DEFS_PORT_H "pin_defs_stm32.h" + +// D-cache clean/invalidate helpers +#if __DCACHE_PRESENT == 1 +#define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size) \ + (SCB_CleanInvalidateDCache_by_Addr((uint32_t*)((uint32_t)addr & ~0x1f), \ + ((uint32_t)((uint8_t*)addr + size + 0x1f) & ~0x1f) - ((uint32_t)addr & ~0x1f))) +#define MP_HAL_CLEAN_DCACHE(addr, size) \ + (SCB_CleanDCache_by_Addr((uint32_t*)((uint32_t)addr & ~0x1f), \ + ((uint32_t)((uint8_t*)addr + size + 0x1f) & ~0x1f) - ((uint32_t)addr & ~0x1f))) +#else +#define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size) +#define MP_HAL_CLEAN_DCACHE(addr, size) +#endif diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 5b78d44450..35b59cbfd8 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -289,8 +289,6 @@ typedef long mp_off_t; // value from disable_irq back to enable_irq. If you really need // to know the machine-specific values, see irq.h. -#include STM32_HAL_H - static inline void enable_irq(mp_uint_t state) { __set_PRIMASK(state); } diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h index 8224c9f5a4..b0387e6447 100644 --- a/ports/stm32/mphalport.h +++ b/ports/stm32/mphalport.h @@ -2,31 +2,6 @@ #include STM32_HAL_H #include "pin.h" -// The unique id address differs per MCU. Ideally this define should -// go in some MCU-specific header, but for now it lives here. -#if defined(MCU_SERIES_F4) -#define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7a10) -#define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size) -#define MP_HAL_CLEAN_DCACHE(addr, size) -#elif defined(MCU_SERIES_F7) -#if defined(STM32F722xx) \ - || defined(STM32F723xx) \ - || defined(STM32F732xx) \ - || defined(STM32F733xx) -#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff07a10) -#else -#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff0f420) -#endif -#define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size) (SCB_CleanInvalidateDCache_by_Addr((uint32_t*)((uint32_t)addr & ~0x1f), ((uint32_t)((uint8_t*)addr + size + 0x1f) & ~0x1f) - ((uint32_t)addr & ~0x1f))) -#define MP_HAL_CLEAN_DCACHE(addr, size) (SCB_CleanDCache_by_Addr((uint32_t*)((uint32_t)addr & ~0x1f), ((uint32_t)((uint8_t*)addr + size + 0x1f) & ~0x1f) - ((uint32_t)addr & ~0x1f))) -#elif defined(MCU_SERIES_L4) -#define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7590) -#define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size) -#define MP_HAL_CLEAN_DCACHE(addr, size) -#else -#error mphalport.h: Unrecognized MCU_SERIES -#endif - extern const unsigned char mp_hal_status_to_errno_table[4]; NORETURN void mp_hal_raise(HAL_StatusTypeDef status); From ae4a07730af7fe4f62f9f61e8b600e39f557925e Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 23 Feb 2018 17:17:32 +1100 Subject: [PATCH 359/828] extmod/vfs_fat: Move ilistdir implementation from misc to main file. The fat_vfs_ilistdir2() function was only used by fat_vfs_ilistdir_func() so moving the former into the same file as the latter allows it to be placed directly into the latter function, thus saving code size. --- extmod/vfs_fat.c | 58 +++++++++++++++++++++++++++++++++++++++++- extmod/vfs_fat.h | 2 -- extmod/vfs_fat_misc.c | 59 ------------------------------------------- 3 files changed, 57 insertions(+), 62 deletions(-) diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 0076df2626..58af0a8e81 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -109,6 +109,52 @@ STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(fat_vfs_mkfs_obj, MP_ROM_PTR(&fat_vfs_mk STATIC MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_open_obj, fatfs_builtin_open_self); +typedef struct _mp_vfs_fat_ilistdir_it_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + bool is_str; + FF_DIR dir; +} mp_vfs_fat_ilistdir_it_t; + +STATIC mp_obj_t mp_vfs_fat_ilistdir_it_iternext(mp_obj_t self_in) { + mp_vfs_fat_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in); + + for (;;) { + FILINFO fno; + FRESULT res = f_readdir(&self->dir, &fno); + char *fn = fno.fname; + if (res != FR_OK || fn[0] == 0) { + // stop on error or end of dir + break; + } + + // Note that FatFS already filters . and .., so we don't need to + + // make 3-tuple with info about this entry + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); + if (self->is_str) { + t->items[0] = mp_obj_new_str(fn, strlen(fn)); + } else { + t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn)); + } + if (fno.fattrib & AM_DIR) { + // dir + t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR); + } else { + // file + t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG); + } + t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number + + return MP_OBJ_FROM_PTR(t); + } + + // ignore error because we may be closing a second time + f_closedir(&self->dir); + + return MP_OBJ_STOP_ITERATION; +} + STATIC mp_obj_t fat_vfs_ilistdir_func(size_t n_args, const mp_obj_t *args) { mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(args[0]); bool is_str_type = true; @@ -122,7 +168,17 @@ STATIC mp_obj_t fat_vfs_ilistdir_func(size_t n_args, const mp_obj_t *args) { path = ""; } - return fat_vfs_ilistdir2(self, path, is_str_type); + // Create a new iterator object to list the dir + mp_vfs_fat_ilistdir_it_t *iter = m_new_obj(mp_vfs_fat_ilistdir_it_t); + iter->base.type = &mp_type_polymorph_iter; + iter->iternext = mp_vfs_fat_ilistdir_it_iternext; + iter->is_str = is_str_type; + FRESULT res = f_opendir(&self->fatfs, &iter->dir, path); + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + + return MP_OBJ_FROM_PTR(iter); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fat_vfs_ilistdir_obj, 1, 2, fat_vfs_ilistdir_func); diff --git a/extmod/vfs_fat.h b/extmod/vfs_fat.h index 688452973c..b6a4795bb4 100644 --- a/extmod/vfs_fat.h +++ b/extmod/vfs_fat.h @@ -60,6 +60,4 @@ mp_import_stat_t fat_vfs_import_stat(struct _fs_user_mount_t *vfs, const char *p mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode); MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_open_obj); -mp_obj_t fat_vfs_ilistdir2(struct _fs_user_mount_t *vfs, const char *path, bool is_str_type); - #endif // MICROPY_INCLUDED_EXTMOD_VFS_FAT_H diff --git a/extmod/vfs_fat_misc.c b/extmod/vfs_fat_misc.c index 1f90ac14ce..d72d9c69c6 100644 --- a/extmod/vfs_fat_misc.c +++ b/extmod/vfs_fat_misc.c @@ -31,65 +31,6 @@ #include "py/runtime.h" #include "lib/oofatfs/ff.h" #include "extmod/vfs_fat.h" -#include "py/lexer.h" - -typedef struct _mp_vfs_fat_ilistdir_it_t { - mp_obj_base_t base; - mp_fun_1_t iternext; - bool is_str; - FF_DIR dir; -} mp_vfs_fat_ilistdir_it_t; - -STATIC mp_obj_t mp_vfs_fat_ilistdir_it_iternext(mp_obj_t self_in) { - mp_vfs_fat_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in); - - for (;;) { - FILINFO fno; - FRESULT res = f_readdir(&self->dir, &fno); - char *fn = fno.fname; - if (res != FR_OK || fn[0] == 0) { - // stop on error or end of dir - break; - } - - // Note that FatFS already filters . and .., so we don't need to - - // make 3-tuple with info about this entry - mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); - if (self->is_str) { - t->items[0] = mp_obj_new_str(fn, strlen(fn)); - } else { - t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn)); - } - if (fno.fattrib & AM_DIR) { - // dir - t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR); - } else { - // file - t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG); - } - t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number - - return MP_OBJ_FROM_PTR(t); - } - - // ignore error because we may be closing a second time - f_closedir(&self->dir); - - return MP_OBJ_STOP_ITERATION; -} - -mp_obj_t fat_vfs_ilistdir2(fs_user_mount_t *vfs, const char *path, bool is_str_type) { - mp_vfs_fat_ilistdir_it_t *iter = m_new_obj(mp_vfs_fat_ilistdir_it_t); - iter->base.type = &mp_type_polymorph_iter; - iter->iternext = mp_vfs_fat_ilistdir_it_iternext; - iter->is_str = is_str_type; - FRESULT res = f_opendir(&vfs->fatfs, &iter->dir, path); - if (res != FR_OK) { - mp_raise_OSError(fresult_to_errno_table[res]); - } - return MP_OBJ_FROM_PTR(iter); -} mp_import_stat_t fat_vfs_import_stat(fs_user_mount_t *vfs, const char *path) { FILINFO fno; From 638b860066ddf6a684ce2d573917b3c8a5817ba2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 23 Feb 2018 17:24:57 +1100 Subject: [PATCH 360/828] extmod/vfs_fat: Merge remaining vfs_fat_misc.c code into vfs_fat.c. The only function left in vfs_fat_misc.c is fat_vfs_import_stat() which can logically go into vfs_fat.c, allowing to remove vfs_fat_misc.c. --- extmod/vfs_fat.c | 14 +++++++++++++ extmod/vfs_fat_misc.c | 49 ------------------------------------------- py/py.mk | 1 - 3 files changed, 14 insertions(+), 50 deletions(-) delete mode 100644 extmod/vfs_fat_misc.c diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 58af0a8e81..e696e0fa83 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -47,6 +47,20 @@ #define mp_obj_fat_vfs_t fs_user_mount_t +mp_import_stat_t fat_vfs_import_stat(fs_user_mount_t *vfs, const char *path) { + FILINFO fno; + assert(vfs != NULL); + FRESULT res = f_stat(&vfs->fatfs, path, &fno); + if (res == FR_OK) { + if ((fno.fattrib & AM_DIR) != 0) { + return MP_IMPORT_STAT_DIR; + } else { + return MP_IMPORT_STAT_FILE; + } + } + return MP_IMPORT_STAT_NO_EXIST; +} + STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 1, 1, false); diff --git a/extmod/vfs_fat_misc.c b/extmod/vfs_fat_misc.c deleted file mode 100644 index d72d9c69c6..0000000000 --- a/extmod/vfs_fat_misc.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2014 Damien P. George - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "py/mpconfig.h" -#if MICROPY_VFS_FAT - -#include -#include "py/runtime.h" -#include "lib/oofatfs/ff.h" -#include "extmod/vfs_fat.h" - -mp_import_stat_t fat_vfs_import_stat(fs_user_mount_t *vfs, const char *path) { - FILINFO fno; - assert(vfs != NULL); - FRESULT res = f_stat(&vfs->fatfs, path, &fno); - if (res == FR_OK) { - if ((fno.fattrib & AM_DIR) != 0) { - return MP_IMPORT_STAT_DIR; - } else { - return MP_IMPORT_STAT_FILE; - } - } - return MP_IMPORT_STAT_NO_EXIST; -} - -#endif // MICROPY_VFS_FAT diff --git a/py/py.mk b/py/py.mk index 879c63248b..7c4cf82d82 100644 --- a/py/py.mk +++ b/py/py.mk @@ -244,7 +244,6 @@ PY_EXTMOD_O_BASENAME = \ extmod/vfs_fat.o \ extmod/vfs_fat_diskio.o \ extmod/vfs_fat_file.o \ - extmod/vfs_fat_misc.o \ extmod/utime_mphal.o \ extmod/uos_dupterm.o \ lib/embed/abort_.o \ From eb570f47a2ec48285fcfab5643301862fa4fe544 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 23 Feb 2018 17:33:26 +1100 Subject: [PATCH 361/828] extmod/vfs_fat: Make fat_vfs_open_obj wrapper public, not its function. This patch just moves the definition of the wrapper object fat_vfs_open_obj to the location of the definition of its function, which matches how it's done in most other places in the code base. --- extmod/vfs_fat.c | 2 -- extmod/vfs_fat.h | 2 +- extmod/vfs_fat_file.c | 3 ++- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index e696e0fa83..0177f5129b 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -121,8 +121,6 @@ STATIC mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_mkfs_fun_obj, fat_vfs_mkfs); STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(fat_vfs_mkfs_obj, MP_ROM_PTR(&fat_vfs_mkfs_fun_obj)); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_open_obj, fatfs_builtin_open_self); - typedef struct _mp_vfs_fat_ilistdir_it_t { mp_obj_base_t base; mp_fun_1_t iternext; diff --git a/extmod/vfs_fat.h b/extmod/vfs_fat.h index b6a4795bb4..14597158fe 100644 --- a/extmod/vfs_fat.h +++ b/extmod/vfs_fat.h @@ -57,7 +57,7 @@ extern const byte fresult_to_errno_table[20]; extern const mp_obj_type_t mp_fat_vfs_type; mp_import_stat_t fat_vfs_import_stat(struct _fs_user_mount_t *vfs, const char *path); -mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode); +MP_DECLARE_CONST_FUN_OBJ_3(fat_vfs_open_obj); MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_open_obj); #endif // MICROPY_INCLUDED_EXTMOD_VFS_FAT_H diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c index 6154c8483f..23e5aa10ff 100644 --- a/extmod/vfs_fat_file.c +++ b/extmod/vfs_fat_file.c @@ -282,7 +282,7 @@ const mp_obj_type_t mp_type_textio = { }; // Factory function for I/O stream classes -mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode) { +STATIC mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode) { // TODO: analyze buffering args and instantiate appropriate type fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS]; @@ -291,5 +291,6 @@ mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode) arg_vals[2].u_obj = mp_const_none; return file_open(self, &mp_type_textio, arg_vals); } +MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_open_obj, fatfs_builtin_open_self); #endif // MICROPY_VFS && MICROPY_VFS_FAT From 2ad555bc760833aae9991a4e6c893daa790c0c89 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 23 Feb 2018 17:41:47 +1100 Subject: [PATCH 362/828] extmod/vfs_fat: Remove declaration of mp_builtin_open_obj. It's declared already in py/builtin.h. --- extmod/vfs_fat.h | 1 - 1 file changed, 1 deletion(-) diff --git a/extmod/vfs_fat.h b/extmod/vfs_fat.h index 14597158fe..da56a90770 100644 --- a/extmod/vfs_fat.h +++ b/extmod/vfs_fat.h @@ -58,6 +58,5 @@ extern const mp_obj_type_t mp_fat_vfs_type; mp_import_stat_t fat_vfs_import_stat(struct _fs_user_mount_t *vfs, const char *path); MP_DECLARE_CONST_FUN_OBJ_3(fat_vfs_open_obj); -MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_open_obj); #endif // MICROPY_INCLUDED_EXTMOD_VFS_FAT_H From 7dfa56e40e9c343cbf4a1726a4babecc69a6b732 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 24 Feb 2018 23:03:17 +1100 Subject: [PATCH 363/828] py/compile: Adjust c_assign_atom_expr() to use return instead of goto. Makes the flow of the function a little more obvious, and allows to reach 100% coverage of compile.c when using gcov. --- py/compile.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/py/compile.c b/py/compile.c index 42ae8a8290..9200b346bd 100644 --- a/py/compile.c +++ b/py/compile.c @@ -376,6 +376,7 @@ STATIC void c_assign_atom_expr(compiler_t *comp, mp_parse_node_struct_t *pns, as EMIT(store_subscr); } } + return; } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_period) { assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0])); if (assign_kind == ASSIGN_AUG_LOAD) { @@ -387,16 +388,10 @@ STATIC void c_assign_atom_expr(compiler_t *comp, mp_parse_node_struct_t *pns, as } EMIT_ARG(store_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0])); } - } else { - goto cannot_assign; + return; } - } else { - goto cannot_assign; } - return; - -cannot_assign: compile_syntax_error(comp, (mp_parse_node_t)pns, "can't assign to expression"); } From c0bcf00ed100181a532240d904395de11addcd33 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 24 Feb 2018 23:10:20 +1100 Subject: [PATCH 364/828] py/asm*.c: Remove unnecessary check for num_locals<0 in asm entry func. All callers of the asm entry function guarantee that num_locals>=0, so no need to add an explicit check for it. Use an assertion instead. Also, the signature of asm_x86_entry is changed to match the other asm entry functions. --- py/asmarm.c | 5 +---- py/asmthumb.c | 5 ++--- py/asmx64.c | 4 +--- py/asmx86.c | 3 ++- py/asmx86.h | 2 +- 5 files changed, 7 insertions(+), 12 deletions(-) diff --git a/py/asmarm.c b/py/asmarm.c index 552fdfb344..1a8923bc23 100644 --- a/py/asmarm.c +++ b/py/asmarm.c @@ -150,10 +150,7 @@ void asm_arm_bkpt(asm_arm_t *as) { // | low address | high address in RAM void asm_arm_entry(asm_arm_t *as, int num_locals) { - - if (num_locals < 0) { - num_locals = 0; - } + assert(num_locals >= 0); as->stack_adjust = 0; as->push_reglist = 1 << ASM_ARM_REG_R1 diff --git a/py/asmthumb.c b/py/asmthumb.c index 5316a7efb2..c5b45f2f51 100644 --- a/py/asmthumb.c +++ b/py/asmthumb.c @@ -104,6 +104,8 @@ STATIC void asm_thumb_write_word32(asm_thumb_t *as, int w32) { // | low address | high address in RAM void asm_thumb_entry(asm_thumb_t *as, int num_locals) { + assert(num_locals >= 0); + // work out what to push and how many extra spaces to reserve on stack // so that we have enough for all locals and it's aligned an 8-byte boundary // we push extra regs (r1, r2, r3) to help do the stack adjustment @@ -111,9 +113,6 @@ void asm_thumb_entry(asm_thumb_t *as, int num_locals) { // for push rlist, lowest numbered register at the lowest address uint reglist; uint stack_adjust; - if (num_locals < 0) { - num_locals = 0; - } // don't pop r0 because it's used for return value switch (num_locals) { case 0: diff --git a/py/asmx64.c b/py/asmx64.c index aa2a8ec7cc..c900a08d1f 100644 --- a/py/asmx64.c +++ b/py/asmx64.c @@ -526,11 +526,9 @@ void asm_x64_jcc_label(asm_x64_t *as, int jcc_type, mp_uint_t label) { } void asm_x64_entry(asm_x64_t *as, int num_locals) { + assert(num_locals >= 0); asm_x64_push_r64(as, ASM_X64_REG_RBP); asm_x64_mov_r64_r64(as, ASM_X64_REG_RBP, ASM_X64_REG_RSP); - if (num_locals < 0) { - num_locals = 0; - } num_locals |= 1; // make it odd so stack is aligned on 16 byte boundary asm_x64_sub_r64_i32(as, ASM_X64_REG_RSP, num_locals * WORD_SIZE); asm_x64_push_r64(as, ASM_X64_REG_RBX); diff --git a/py/asmx86.c b/py/asmx86.c index 6a78fbd5ea..3938baaacb 100644 --- a/py/asmx86.c +++ b/py/asmx86.c @@ -387,7 +387,8 @@ void asm_x86_jcc_label(asm_x86_t *as, mp_uint_t jcc_type, mp_uint_t label) { } } -void asm_x86_entry(asm_x86_t *as, mp_uint_t num_locals) { +void asm_x86_entry(asm_x86_t *as, int num_locals) { + assert(num_locals >= 0); asm_x86_push_r32(as, ASM_X86_REG_EBP); asm_x86_mov_r32_r32(as, ASM_X86_REG_EBP, ASM_X86_REG_ESP); if (num_locals > 0) { diff --git a/py/asmx86.h b/py/asmx86.h index bd58954531..09559850ca 100644 --- a/py/asmx86.h +++ b/py/asmx86.h @@ -104,7 +104,7 @@ void asm_x86_test_r8_with_r8(asm_x86_t* as, int src_r32_a, int src_r32_b); void asm_x86_setcc_r8(asm_x86_t* as, mp_uint_t jcc_type, int dest_r8); void asm_x86_jmp_label(asm_x86_t* as, mp_uint_t label); void asm_x86_jcc_label(asm_x86_t* as, mp_uint_t jcc_type, mp_uint_t label); -void asm_x86_entry(asm_x86_t* as, mp_uint_t num_locals); +void asm_x86_entry(asm_x86_t* as, int num_locals); void asm_x86_exit(asm_x86_t* as); void asm_x86_mov_arg_to_r32(asm_x86_t *as, int src_arg_num, int dest_r32); void asm_x86_mov_local_to_r32(asm_x86_t* as, int src_local_num, int dest_r32); From 90da791a08bee6e4d9706dd80f9c15f22ff4c50f Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 24 Feb 2018 23:13:42 +1100 Subject: [PATCH 365/828] tests/basics: Add test for calling a subclass of a native class. Adding this test gets py/objtype.c to 100% coverage. --- tests/basics/subclass_native_call.py | 30 ++++++++++++++++++++++++ tests/basics/subclass_native_call.py.exp | 1 + 2 files changed, 31 insertions(+) create mode 100644 tests/basics/subclass_native_call.py create mode 100644 tests/basics/subclass_native_call.py.exp diff --git a/tests/basics/subclass_native_call.py b/tests/basics/subclass_native_call.py new file mode 100644 index 0000000000..c645575225 --- /dev/null +++ b/tests/basics/subclass_native_call.py @@ -0,0 +1,30 @@ +# test calling a subclass of a native class that supports calling + +# For this test we need a native class that can be subclassed (has make_new) +# and is callable (has call). The only one available is machine.Signal, which +# in turns needs PinBase. +try: + import umachine as machine +except ImportError: + import machine +try: + machine.PinBase + machine.Signal +except AttributeError: + print("SKIP") + raise SystemExit + +class Pin(machine.PinBase): + #def __init__(self): + # self.v = 0 + + def value(self, v=None): + return 42 + +class MySignal(machine.Signal): + pass + +s = MySignal(Pin()) + +# apply call to the subclass, which should call the native base +print(s()) diff --git a/tests/basics/subclass_native_call.py.exp b/tests/basics/subclass_native_call.py.exp new file mode 100644 index 0000000000..d81cc0710e --- /dev/null +++ b/tests/basics/subclass_native_call.py.exp @@ -0,0 +1 @@ +42 From 77a62d8b5add1c6feea307a2b6c23552cdac05ce Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 24 Feb 2018 23:14:39 +1100 Subject: [PATCH 366/828] tests/stress: Add test to create a dict beyond "maximum" rehash size. There is a finite list of ascending primes used for the size of a hash table, and this test tests that the code can handle a dict larger than the maximum value in that list of primes. Adding this tests gets py/map.c to 100% coverage. --- tests/stress/dict_create_max.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/stress/dict_create_max.py diff --git a/tests/stress/dict_create_max.py b/tests/stress/dict_create_max.py new file mode 100644 index 0000000000..3c75db20da --- /dev/null +++ b/tests/stress/dict_create_max.py @@ -0,0 +1,13 @@ +# The aim with this test is to hit the maximum resize/rehash size of a dict, +# where there are no more primes in the table of growing allocation sizes. +# This value is 54907 items. + +d = {} +try: + for i in range(54908): + d[i] = i +except MemoryError: + pass + +# Just check the dict still has the first value +print(d[0]) From f75c7ad1a9dcfa2cfe5ccd12dda7c396a6bd973c Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 25 Feb 2018 22:59:19 +1100 Subject: [PATCH 367/828] py/mpz: In mpz_clone, remove unused check for NULL dig. This path for src->deg==NULL is never used because mpz_clone() is always called with an argument that has a non-zero integer value, and hence has some digits allocated to it (mpz_clone() is a static function private to mpz.c all callers of this function first check if the integer value is zero and if so take a special-case path, bypassing the call to mpz_clone()). There is some unused and commented-out functions that may actually pass a zero-valued mpz to mpz_clone(), so some TODOs are added to these function in case they are needed in the future. --- py/mpz.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/py/mpz.c b/py/mpz.c index 380e8968e6..fa50868620 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -705,17 +705,14 @@ STATIC void mpz_need_dig(mpz_t *z, size_t need) { } STATIC mpz_t *mpz_clone(const mpz_t *src) { + assert(src->alloc != 0); mpz_t *z = m_new_obj(mpz_t); z->neg = src->neg; z->fixed_dig = 0; z->alloc = src->alloc; z->len = src->len; - if (src->dig == NULL) { - z->dig = NULL; - } else { - z->dig = m_new(mpz_dig_t, z->alloc); - memcpy(z->dig, src->dig, src->alloc * sizeof(mpz_dig_t)); - } + z->dig = m_new(mpz_dig_t, z->alloc); + memcpy(z->dig, src->dig, src->alloc * sizeof(mpz_dig_t)); return z; } @@ -983,6 +980,7 @@ these functions are unused /* returns abs(z) */ mpz_t *mpz_abs(const mpz_t *z) { + // TODO: handle case of z->alloc=0 mpz_t *z2 = mpz_clone(z); z2->neg = 0; return z2; @@ -991,6 +989,7 @@ mpz_t *mpz_abs(const mpz_t *z) { /* returns -z */ mpz_t *mpz_neg(const mpz_t *z) { + // TODO: handle case of z->alloc=0 mpz_t *z2 = mpz_clone(z); z2->neg = 1 - z2->neg; return z2; @@ -1408,6 +1407,7 @@ these functions are unused */ mpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2) { if (z1->len == 0) { + // TODO: handle case of z2->alloc=0 mpz_t *a = mpz_clone(z2); a->neg = 0; return a; From 62be14d77c1c61c7636e9ffe6b7e0c744ace58c6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 25 Feb 2018 23:43:16 +1100 Subject: [PATCH 368/828] tests/unix: Add coverage tests for mpz_set_from_float, mpz_mul_inpl. These new tests cover cases that can't be reached from Python and get coverage of py/mpz.c to 100%. These "unreachable from Python" pieces of code could be removed but they form an integral part of the mpz C API and may be useful for non-Python usage of mpz. --- ports/unix/coverage.c | 33 ++++++++++++++++++++++++++++++++ tests/unix/extra_coverage.py.exp | 6 ++++++ 2 files changed, 39 insertions(+) diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 6b6b892856..25376edc02 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -262,6 +262,39 @@ STATIC mp_obj_t extra_coverage(void) { mpz_set_from_int(&mpz, 1); mpz_shl_inpl(&mpz, &mpz, 70); mp_printf(&mp_plat_print, "%d\n", mpz_as_uint_checked(&mpz, &value)); + + // mpz_set_from_float with inf as argument + mpz_set_from_float(&mpz, 1.0 / 0.0); + mpz_as_uint_checked(&mpz, &value); + mp_printf(&mp_plat_print, "%d\n", (int)value); + + // mpz_set_from_float with 0 as argument + mpz_set_from_float(&mpz, 0); + mpz_as_uint_checked(&mpz, &value); + mp_printf(&mp_plat_print, "%d\n", (int)value); + + // mpz_set_from_float with 0 Date: Mon, 26 Feb 2018 13:36:13 +1100 Subject: [PATCH 369/828] tests/extmod/vfs_fat_fileio1: Add test for failing alloc with finaliser. --- tests/extmod/vfs_fat_fileio1.py | 12 ++++++++++++ tests/extmod/vfs_fat_fileio1.py.exp | 1 + 2 files changed, 13 insertions(+) diff --git a/tests/extmod/vfs_fat_fileio1.py b/tests/extmod/vfs_fat_fileio1.py index 8b9ff92eb8..8c8ec57472 100644 --- a/tests/extmod/vfs_fat_fileio1.py +++ b/tests/extmod/vfs_fat_fileio1.py @@ -113,3 +113,15 @@ except OSError as e: vfs.remove("foo_file.txt") print(list(vfs.ilistdir())) + +# Here we test that opening a file with the heap locked fails correctly. This +# is a special case because file objects use a finaliser and allocating with a +# finaliser is a different path to normal allocation. It would be better to +# test this in the core tests but there are no core objects that use finaliser. +import micropython +micropython.heap_lock() +try: + vfs.open('x', 'r') +except MemoryError: + print('MemoryError') +micropython.heap_unlock() diff --git a/tests/extmod/vfs_fat_fileio1.py.exp b/tests/extmod/vfs_fat_fileio1.py.exp index a66f07605c..a304c75d96 100644 --- a/tests/extmod/vfs_fat_fileio1.py.exp +++ b/tests/extmod/vfs_fat_fileio1.py.exp @@ -11,3 +11,4 @@ o d True [('foo_dir', 16384, 0)] +MemoryError From 4c2230add8bbc40a0c86327c5e21ba10f78623b9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 26 Feb 2018 13:36:55 +1100 Subject: [PATCH 370/828] tests/extmod/uzlib_decompress: Add uzlib tests to improve coverage. --- tests/extmod/uzlib_decompress.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/extmod/uzlib_decompress.py b/tests/extmod/uzlib_decompress.py index 63247955c9..dd6e4876fa 100644 --- a/tests/extmod/uzlib_decompress.py +++ b/tests/extmod/uzlib_decompress.py @@ -15,7 +15,9 @@ PATTERNS = [ (bytes(range(64)), b'x\x9cc`dbfaec\xe7\xe0\xe4\xe2\xe6\xe1\xe5\xe3\x17\x10\x14\x12\x16\x11\x15\x13\x97\x90\x94\x92\x96\x91\x95\x93WPTRVQUS\xd7\xd0\xd4\xd2\xd6\xd1\xd5\xd370426153\xb7\xb0\xb4\xb2\xb6\xb1\xb5\xb3\x07\x00\xaa\xe0\x07\xe1'), (b'hello', b'x\x01\x01\x05\x00\xfa\xffhello\x06,\x02\x15'), # compression level 0 # adaptive/dynamic huffman tree - (b'13371813150|13764518736|12345678901', b'x\x9c\x05\xc1\x81\x01\x000\x04\x04\xb1\x95\\\x1f\xcfn\x86o\x82d\x06Qq\xc8\x9d\xc5X}I}\x00\x951D>I}\x00\x951D>I}\x00\x951D>I}\x00\x951D', b'x\x9c\x05\xc11\x01\x00\x00\x00\x010\x95\x14py\x84\x12C_\x9bR\x8cV\x8a\xd1J1Z)F\x1fw`\x089'), ] for unpacked, packed in PATTERNS: @@ -41,3 +43,9 @@ try: zlib.decompress(b'abc') except Exception: print("Exception") + +# invalid block type +try: + zlib.decompress(b'\x07', -15) # final-block, block-type=3 (invalid) +except Exception as er: + print('Exception') From 6dad0885692f8d1e743873fb4be241f1fd1cb91a Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 26 Feb 2018 15:54:03 +1100 Subject: [PATCH 371/828] tests/float: Adjust float-parsing tests to pass with only a small error. Float parsing (both single and double precision) may have a relative error of order the floating point precision, so adjust tests to take this into account by not printing all of the digits of the answer. --- tests/float/float_parse.py | 5 ++--- tests/float/float_parse_doubleprec.py | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/float/float_parse.py b/tests/float/float_parse.py index de4ea455fb..5eb16e79cf 100644 --- a/tests/float/float_parse.py +++ b/tests/float/float_parse.py @@ -7,9 +7,8 @@ print(float('1234') - float('0.1234e4')) print(float('1.015625') - float('1015625e-6')) # very large integer part with a very negative exponent should cancel out -print(float('9' * 60 + 'e-60')) -print(float('9' * 60 + 'e-40')) -print(float('9' * 60 + 'e-20') == float('1e40')) +print('%.4e' % float('9' * 60 + 'e-60')) +print('%.4e' % float('9' * 60 + 'e-40')) # many fractional digits print(float('.' + '9' * 70)) diff --git a/tests/float/float_parse_doubleprec.py b/tests/float/float_parse_doubleprec.py index 2ea7842f3f..dcc0dd5921 100644 --- a/tests/float/float_parse_doubleprec.py +++ b/tests/float/float_parse_doubleprec.py @@ -11,9 +11,9 @@ print(float('.' + '9' * 400 + 'e100')) print(float('.' + '9' * 400 + 'e-100')) # tiny fraction with large exponent -print(float('.' + '0' * 400 + '9e100')) -print(float('.' + '0' * 400 + '9e200')) -print(float('.' + '0' * 400 + '9e400')) +print('%.14e' % float('.' + '0' * 400 + '9e100')) +print('%.14e' % float('.' + '0' * 400 + '9e200')) +print('%.14e' % float('.' + '0' * 400 + '9e400')) # ensure that accuracy is retained when value is close to a subnormal print(float('1.00000000000000000000e-307')) From 9d8347a9aac40f8cc168b0226c2e74f776a7d4bf Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 26 Feb 2018 16:08:58 +1100 Subject: [PATCH 372/828] py/mpstate.h: Add repl_line state for MICROPY_REPL_EVENT_DRIVEN. --- py/mpstate.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/py/mpstate.h b/py/mpstate.h index a7ffbbf3cb..816698f4e2 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -166,6 +166,10 @@ typedef struct _mp_state_vm_t { // root pointers for extmod + #if MICROPY_REPL_EVENT_DRIVEN + vstr_t *repl_line; + #endif + #if MICROPY_PY_OS_DUPTERM mp_obj_t dupterm_objs[MICROPY_PY_OS_DUPTERM]; mp_obj_t dupterm_arr_obj; From 01dcd5bb71ceba99cf33f82491fbb88ac4f58ec5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 26 Feb 2018 16:09:33 +1100 Subject: [PATCH 373/828] esp8266/uart: Allow to compile with event-driven REPL. --- ports/esp8266/uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp8266/uart.c b/ports/esp8266/uart.c index 6c1f9e095d..ec944a97cc 100644 --- a/ports/esp8266/uart.c +++ b/ports/esp8266/uart.c @@ -276,7 +276,7 @@ void uart_task_handler(os_event_t *evt) { int c, ret = 0; while ((c = ringbuf_get(&input_buf)) >= 0) { - if (c == interrupt_char) { + if (c == mp_interrupt_char) { mp_keyboard_interrupt(); } ret = pyexec_event_repl_process_char(c); From c5fe610ba15468e1d92d7b6d5f5962f7595e3324 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 26 Feb 2018 16:41:13 +1100 Subject: [PATCH 374/828] esp8266/modnetwork: Implement WLAN.status('rssi') for STA interface. This will return the RSSI of the AP that the STA is connected to. --- docs/library/network.rst | 6 +++++- ports/esp8266/modnetwork.c | 24 ++++++++++++++++++------ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/docs/library/network.rst b/docs/library/network.rst index a1190a5740..a113209e0e 100644 --- a/docs/library/network.rst +++ b/docs/library/network.rst @@ -383,10 +383,11 @@ parameter should be `id`. * 0 -- visible * 1 -- hidden - .. method:: wlan.status() + .. method:: wlan.status([param]) Return the current status of the wireless connection. + When called with no argument the return value describes the network link status. The possible statuses are defined as constants: * ``STAT_IDLE`` -- no connection and no activity, @@ -396,6 +397,9 @@ parameter should be `id`. * ``STAT_CONNECT_FAIL`` -- failed due to other problems, * ``STAT_GOT_IP`` -- connection successful. + When called with one argument *param* should be a string naming the status + parameter to retrieve. Supported parameters in WiFI STA mode are: ``'rssi'``. + .. method:: wlan.isconnected() In case of STA mode, returns ``True`` if connected to a WiFi access diff --git a/ports/esp8266/modnetwork.c b/ports/esp8266/modnetwork.c index f7da5b7510..00a84c446e 100644 --- a/ports/esp8266/modnetwork.c +++ b/ports/esp8266/modnetwork.c @@ -150,14 +150,26 @@ STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_disconnect_obj, esp_disconnect); -STATIC mp_obj_t esp_status(mp_obj_t self_in) { - wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (self->if_id == STATION_IF) { - return MP_OBJ_NEW_SMALL_INT(wifi_station_get_connect_status()); +STATIC mp_obj_t esp_status(size_t n_args, const mp_obj_t *args) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + // Get link status + if (self->if_id == STATION_IF) { + return MP_OBJ_NEW_SMALL_INT(wifi_station_get_connect_status()); + } + return MP_OBJ_NEW_SMALL_INT(-1); + } else { + // Get specific status parameter + switch (mp_obj_str_get_qstr(args[1])) { + case MP_QSTR_rssi: + if (self->if_id == STATION_IF) { + return MP_OBJ_NEW_SMALL_INT(wifi_station_get_rssi()); + } + } + mp_raise_ValueError("unknown status param"); } - return MP_OBJ_NEW_SMALL_INT(-1); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_status_obj, esp_status); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_status_obj, 1, 2, esp_status); STATIC mp_obj_t *esp_scan_list = NULL; From 22ade2f5c4ac88c90a013cbf4b81c8d795487f33 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 27 Feb 2018 15:39:31 +1100 Subject: [PATCH 375/828] py/vm: Fix case of handling raised StopIteration within yield from. This patch concerns the handling of an NLR-raised StopIteration, raised during a call to mp_resume() which is handling the yield from opcode. Previously, commit 6738c1dded8e436686f85008ec0a4fc47406ab7a introduced code to handle this case, along with a test. It seems that it was lucky that the test worked because the code did not correctly handle the stack pointer (sp). Furthermore, commit 79d996a57b351e0ef354eb1e2f644b194433cc73 improved the way mp_resume() propagated certain exceptions: it changed raising an NLR value to returning MP_VM_RETURN_EXCEPTION. This change meant that the test introduced in gen_yield_from_ducktype.py was no longer hitting the code introduced in 6738c1dded8e436686f85008ec0a4fc47406ab7a. The patch here does two things: 1. Fixes the handling of sp in the VM for the case that yield from is interrupted by a StopIteration raised via NLR. 2. Introduces a new test to check this handling of sp and re-covers the code in the VM. --- py/vm.c | 4 +++- tests/basics/gen_yield_from.py | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/py/vm.c b/py/vm.c index ceb2060f9d..416de6b1a3 100644 --- a/py/vm.c +++ b/py/vm.c @@ -1162,6 +1162,7 @@ yield: mp_obj_t send_value = POP(); mp_obj_t t_exc = MP_OBJ_NULL; mp_obj_t ret_value; + code_state->sp = sp; // Save sp because it's needed if mp_resume raises StopIteration if (inject_exc != MP_OBJ_NULL) { t_exc = inject_exc; inject_exc = MP_OBJ_NULL; @@ -1361,7 +1362,8 @@ exception_handler: } else if (*code_state->ip == MP_BC_YIELD_FROM) { // StopIteration inside yield from call means return a value of // yield from, so inject exception's value as yield from's result - *++code_state->sp = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(nlr.ret_val)); + // (Instead of stack pop then push we just replace exhausted gen with value) + *code_state->sp = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(nlr.ret_val)); code_state->ip++; // yield from is over, move to next instruction goto outer_dispatch_loop; // continue with dispatch loop } diff --git a/tests/basics/gen_yield_from.py b/tests/basics/gen_yield_from.py index 5196b48d2b..4e68aec63b 100644 --- a/tests/basics/gen_yield_from.py +++ b/tests/basics/gen_yield_from.py @@ -40,3 +40,16 @@ def gen6(): g = gen6() print(list(g)) + +# StopIteration from within a Python function, within a native iterator (map), within a yield from +def gen7(x): + if x < 3: + return x + else: + raise StopIteration(444) + +def gen8(): + print((yield from map(gen7, range(100)))) + +g = gen8() +print(list(g)) From a9f6d4921829195d7310aa8b07a4a705577161a5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 27 Feb 2018 15:48:09 +1100 Subject: [PATCH 376/828] py/vm: Simplify handling of special-case STOP_ITERATION in yield from. There's no need to have MP_OBJ_NULL a special case, the code can re-use the MP_OBJ_STOP_ITERATION value to signal the special case and the VM can detect this with only one check (for MP_OBJ_STOP_ITERATION). --- py/runtime.c | 3 +-- py/vm.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/py/runtime.c b/py/runtime.c index 65d0df639e..54ec0d70b4 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1215,13 +1215,12 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th if (type->iternext != NULL && send_value == mp_const_none) { mp_obj_t ret = type->iternext(self_in); + *ret_val = ret; if (ret != MP_OBJ_STOP_ITERATION) { - *ret_val = ret; return MP_VM_RETURN_YIELD; } else { // Emulate raise StopIteration() // Special case, handled in vm.c - *ret_val = MP_OBJ_NULL; return MP_VM_RETURN_NORMAL; } } diff --git a/py/vm.c b/py/vm.c index 416de6b1a3..2a8e3c990c 100644 --- a/py/vm.c +++ b/py/vm.c @@ -1178,8 +1178,7 @@ yield: } else if (ret_kind == MP_VM_RETURN_NORMAL) { // Pop exhausted gen sp--; - // TODO: When ret_value can be MP_OBJ_NULL here?? - if (ret_value == MP_OBJ_NULL || ret_value == MP_OBJ_STOP_ITERATION) { + if (ret_value == MP_OBJ_STOP_ITERATION) { // Optimize StopIteration // TODO: get StopIteration's value PUSH(mp_const_none); From d3cac18d4914af4549437ef3fd0d62f1fc05ff27 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 27 Feb 2018 16:17:10 +1100 Subject: [PATCH 377/828] tests/unix: Add coverage test for VM executing invalid bytecode. --- ports/unix/coverage.c | 18 ++++++++++++++++++ tests/unix/extra_coverage.py.exp | 2 ++ 2 files changed, 20 insertions(+) diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 25376edc02..f0d9406c61 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -11,6 +11,7 @@ #include "py/formatfloat.h" #include "py/stream.h" #include "py/binary.h" +#include "py/bc.h" #if defined(MICROPY_UNIX_COVERAGE) @@ -350,6 +351,23 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "%.0lf\n", dar[0]); } + // VM + { + mp_printf(&mp_plat_print, "# VM\n"); + + // call mp_execute_bytecode with invalide bytecode (should raise NotImplementedError) + mp_obj_fun_bc_t fun_bc; + fun_bc.bytecode = (const byte*)"\x01"; // just needed for n_state + mp_code_state_t *code_state = m_new_obj_var(mp_code_state_t, mp_obj_t, 1); + code_state->fun_bc = &fun_bc; + code_state->ip = (const byte*)"\x00"; // just needed for an invalid opcode + code_state->sp = &code_state->state[0]; + code_state->exc_sp = NULL; + code_state->old_globals = NULL; + mp_vm_return_kind_t ret = mp_execute_bytecode(code_state, MP_OBJ_NULL); + mp_printf(&mp_plat_print, "%d %d\n", ret, mp_obj_get_type(code_state->state[0]) == &mp_type_NotImplementedError); + } + // scheduler { mp_printf(&mp_plat_print, "# scheduler\n"); diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index 71b6867ca6..a030155ba8 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -58,6 +58,8 @@ Warning: test # binary 122 456 +# VM +2 1 # scheduler sched(0)=1 sched(1)=1 From 439acddc6052f112e8c2e57a6d50c7569344a6bf Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 27 Feb 2018 22:39:17 +1100 Subject: [PATCH 378/828] tests/basics/gc1: Add test which triggers GC threshold. --- tests/basics/gc1.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/basics/gc1.py b/tests/basics/gc1.py index dcbe0bfcf6..332bf9744c 100644 --- a/tests/basics/gc1.py +++ b/tests/basics/gc1.py @@ -27,3 +27,8 @@ if hasattr(gc, 'threshold'): assert(gc.threshold() == 0) assert(gc.threshold(-1) is None) assert(gc.threshold() == -1) + + # Setting a low threshold should trigger collection at the list alloc + gc.threshold(1) + [[], []] + gc.threshold(-1) From 09be031e047f0e7ba77620c29c5abbdbd5e3d055 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 28 Feb 2018 15:11:20 +1100 Subject: [PATCH 379/828] extmod/vfs_fat_diskio: Use a C-stack-allocated bytearray for block buf. This patch eliminates heap allocation in the VFS FAT disk IO layer, when calling the underlying readblocks/writeblocks methods. The bytearray object that is passed to these methods is now allocated on the C stack rather than the heap (it's only 4 words big). This means that these methods should not retain a pointer to the buffer object that is passed in, but this was already a restriction because the original heap-allocated bytearray had its buffer passed by reference. --- extmod/vfs_fat_diskio.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/extmod/vfs_fat_diskio.c b/extmod/vfs_fat_diskio.c index ff23c6b0cd..712038f3e9 100644 --- a/extmod/vfs_fat_diskio.c +++ b/extmod/vfs_fat_diskio.c @@ -36,6 +36,8 @@ #include "py/mphal.h" #include "py/runtime.h" +#include "py/binary.h" +#include "py/objarray.h" #include "lib/oofatfs/ff.h" #include "lib/oofatfs/diskio.h" #include "extmod/vfs_fat.h" @@ -126,8 +128,9 @@ DRESULT disk_read ( return RES_ERROR; } } else { + mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, count * SECSIZE(&vfs->fatfs), buff}; vfs->readblocks[2] = MP_OBJ_NEW_SMALL_INT(sector); - vfs->readblocks[3] = mp_obj_new_bytearray_by_ref(count * SECSIZE(&vfs->fatfs), buff); + vfs->readblocks[3] = MP_OBJ_FROM_PTR(&ar); mp_call_method_n_kw(2, 0, vfs->readblocks); // TODO handle error return } @@ -162,8 +165,9 @@ DRESULT disk_write ( return RES_ERROR; } } else { + mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, count * SECSIZE(&vfs->fatfs), (void*)buff}; vfs->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(sector); - vfs->writeblocks[3] = mp_obj_new_bytearray_by_ref(count * SECSIZE(&vfs->fatfs), (void*)buff); + vfs->writeblocks[3] = MP_OBJ_FROM_PTR(&ar); mp_call_method_n_kw(2, 0, vfs->writeblocks); // TODO handle error return } From 90e719a232dbf4039085d4fea2faf1358e408e40 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 28 Feb 2018 15:27:51 +1100 Subject: [PATCH 380/828] tests/extmod/vfs_fat_fileio1: Add test for calling file obj finaliser. --- tests/extmod/vfs_fat_fileio1.py | 14 ++++++++++++++ tests/extmod/vfs_fat_fileio1.py.exp | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/tests/extmod/vfs_fat_fileio1.py b/tests/extmod/vfs_fat_fileio1.py index 8c8ec57472..f1f4639ab7 100644 --- a/tests/extmod/vfs_fat_fileio1.py +++ b/tests/extmod/vfs_fat_fileio1.py @@ -125,3 +125,17 @@ try: except MemoryError: print('MemoryError') micropython.heap_unlock() + +# Here we test that the finaliser is actually called during a garbage collection. +import gc +N = 4 +for i in range(N): + n = 'x%d' % i + f = vfs.open(n, 'w') + f.write(n) + f = None # release f without closing + [0, 1, 2, 3] # use up Python stack so f is really gone +gc.collect() # should finalise all N files by closing them +for i in range(N): + with vfs.open('x%d' % i, 'r') as f: + print(f.read()) diff --git a/tests/extmod/vfs_fat_fileio1.py.exp b/tests/extmod/vfs_fat_fileio1.py.exp index a304c75d96..2d4792aa3b 100644 --- a/tests/extmod/vfs_fat_fileio1.py.exp +++ b/tests/extmod/vfs_fat_fileio1.py.exp @@ -12,3 +12,7 @@ d True [('foo_dir', 16384, 0)] MemoryError +x0 +x1 +x2 +x3 From bc12eca461a317df842ce2e616afa97670cd0ce3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Mar 2018 15:47:17 +1100 Subject: [PATCH 381/828] py/formatfloat: Fix rounding of %f format with edge-case FP values. Prior to this patch the %f formatting of some FP values could be off by up to 1, eg '%.0f' % 123 would return "122" (unix x64). Depending on the FP precision (single vs double) certain numbers would format correctly, but others wolud not. This patch should fix all cases of rounding for %f. --- py/formatfloat.c | 2 +- tests/float/float_format.py | 11 +++++++++++ tests/unix/extra_coverage.py.exp | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 tests/float/float_format.py diff --git a/py/formatfloat.c b/py/formatfloat.c index 4228f99ff5..22dd8aaacc 100644 --- a/py/formatfloat.c +++ b/py/formatfloat.c @@ -341,7 +341,7 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch // Round // If we print non-exponential format (i.e. 'f'), but a digit we're going // to round by (e) is too far away, then there's nothing to round. - if ((org_fmt != 'f' || e <= 1) && f >= FPCONST(5.0)) { + if ((org_fmt != 'f' || e <= num_digits) && f >= FPCONST(5.0)) { char *rs = s; rs--; while (1) { diff --git a/tests/float/float_format.py b/tests/float/float_format.py new file mode 100644 index 0000000000..4d5ad1d693 --- /dev/null +++ b/tests/float/float_format.py @@ -0,0 +1,11 @@ +# test float formatting + +# general rounding +for val in (116, 1111, 1234, 5010, 11111): + print('%.0f' % val) + print('%.1f' % val) + print('%.3f' % val) + +# make sure rounding is done at the correct precision +for prec in range(8): + print(('%%.%df' % prec) % 6e-5) diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index a030155ba8..54e19d14ac 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -56,7 +56,7 @@ Warning: test +1e+00 +1e+00 # binary -122 +123 456 # VM 2 1 From 7b050fa76c6a763043739d40c82dde839d7f8fd9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Mar 2018 16:02:59 +1100 Subject: [PATCH 382/828] py/formatfloat: Fix case where floats could render with a ":" character. Prior to this patch, some architectures (eg unix x86) could render floats with a ":" character in them, eg 1e+39 would come out as ":e+38" (":" is just after "9" in ASCII so this is like 10e+38). This patch fixes some of these cases. --- py/formatfloat.c | 2 +- tests/float/float_format.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/py/formatfloat.c b/py/formatfloat.c index 22dd8aaacc..60dcee6f54 100644 --- a/py/formatfloat.c +++ b/py/formatfloat.c @@ -258,7 +258,7 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch } // It can be that f was right on the edge of an entry in pos_pow needs to be reduced - if (f >= FPCONST(10.0)) { + if ((int)f >= 10) { e += 1; f *= FPCONST(0.1); } diff --git a/tests/float/float_format.py b/tests/float/float_format.py index 4d5ad1d693..cda395ce02 100644 --- a/tests/float/float_format.py +++ b/tests/float/float_format.py @@ -9,3 +9,7 @@ for val in (116, 1111, 1234, 5010, 11111): # make sure rounding is done at the correct precision for prec in range(8): print(('%%.%df' % prec) % 6e-5) + +# check certain cases that had a digit value of 10 render as a ":" character +print('%.2e' % float('9' * 51 + 'e-39')) +print('%.2e' % float('9' * 40 + 'e-21')) From 955ee6477f4b1d3a70bfe97a1e7727848bf2d06d Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Mar 2018 17:00:02 +1100 Subject: [PATCH 383/828] py/formatfloat: Fix case where floats could render with negative digits. Prior to this patch, some architectures (eg unix x86) could render floats with "negative" digits, like ")". For example, '%.23e' % 1e-80 would come out as "1.0000000000000000/)/(,*0e-80". This patch fixes the known cases. --- py/formatfloat.c | 6 +++++- tests/float/float_format.py | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/py/formatfloat.c b/py/formatfloat.c index 60dcee6f54..dc7fc1d1fd 100644 --- a/py/formatfloat.c +++ b/py/formatfloat.c @@ -330,7 +330,11 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch // Print the digits of the mantissa for (int i = 0; i < num_digits; ++i, --dec) { int32_t d = (int32_t)f; - *s++ = '0' + d; + if (d < 0) { + *s++ = '0'; + } else { + *s++ = '0' + d; + } if (dec == 0 && prec > 0) { *s++ = '.'; } diff --git a/tests/float/float_format.py b/tests/float/float_format.py index cda395ce02..d43535cf2f 100644 --- a/tests/float/float_format.py +++ b/tests/float/float_format.py @@ -13,3 +13,7 @@ for prec in range(8): # check certain cases that had a digit value of 10 render as a ":" character print('%.2e' % float('9' * 51 + 'e-39')) print('%.2e' % float('9' * 40 + 'e-21')) + +# check a case that would render negative digit values, eg ")" characters +# the string is converted back to a float to check for no illegal characters +float('%.23e' % 1e-80) From c3f1b2233865f4e7f3016ca22a65ef9f4d4ec4db Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Mar 2018 22:49:15 +1100 Subject: [PATCH 384/828] tests/unix: Add coverage tests for various GC calls. --- ports/unix/coverage.c | 24 ++++++++++++++++++++++++ tests/unix/extra_coverage.py.exp | 4 ++++ 2 files changed, 28 insertions(+) diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index f0d9406c61..db97f4f774 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -4,6 +4,7 @@ #include "py/obj.h" #include "py/objstr.h" #include "py/runtime.h" +#include "py/gc.h" #include "py/repl.h" #include "py/mpz.h" #include "py/builtin.h" @@ -159,6 +160,29 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "abc\n%"); // string ends in middle of format specifier } + // GC + { + mp_printf(&mp_plat_print, "# GC\n"); + + // calling gc_free while GC is locked + gc_lock(); + gc_free(NULL); + gc_unlock(); + + // calling gc_realloc while GC is locked + void *p = gc_alloc(4, false); + gc_lock(); + mp_printf(&mp_plat_print, "%p\n", gc_realloc(p, 8, true)); + gc_unlock(); + + // using gc_realloc to resize to 0, which means free the memory + p = gc_alloc(4, false); + mp_printf(&mp_plat_print, "%p\n", gc_realloc(p, 0, false)); + + // calling gc_nbytes with a non-heap pointer + mp_printf(&mp_plat_print, "%p\n", gc_nbytes(NULL)); + } + // vstr { mp_printf(&mp_plat_print, "# vstr\n"); diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index 54e19d14ac..a686e71615 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -13,6 +13,10 @@ false true 80000000 80000000 abc +# GC +0 +0 +0 # vstr tests sts From c607b58efe9333ab92e1b721dcd974e35a9d393e Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Mar 2018 10:59:09 +1100 Subject: [PATCH 385/828] tests: Move heap-realloc-while-locked test from C to Python. This test for calling gc_realloc() while the GC is locked can be done in pure Python, so better to do it that way since it can then be tested on more ports. --- ports/unix/coverage.c | 8 +------- tests/micropython/heap_lock.py | 11 +++++++++++ tests/micropython/heap_lock.py.exp | 1 + tests/unix/extra_coverage.py.exp | 1 - 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index db97f4f774..33533ad865 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -169,14 +169,8 @@ STATIC mp_obj_t extra_coverage(void) { gc_free(NULL); gc_unlock(); - // calling gc_realloc while GC is locked - void *p = gc_alloc(4, false); - gc_lock(); - mp_printf(&mp_plat_print, "%p\n", gc_realloc(p, 8, true)); - gc_unlock(); - // using gc_realloc to resize to 0, which means free the memory - p = gc_alloc(4, false); + void *p = gc_alloc(4, false); mp_printf(&mp_plat_print, "%p\n", gc_realloc(p, 0, false)); // calling gc_nbytes with a non-heap pointer diff --git a/tests/micropython/heap_lock.py b/tests/micropython/heap_lock.py index 0f0a70eff1..ca3f5806a8 100644 --- a/tests/micropython/heap_lock.py +++ b/tests/micropython/heap_lock.py @@ -2,13 +2,24 @@ import micropython +l = [] +l2 = list(range(100)) + micropython.heap_lock() +# general allocation on the heap try: print([]) except MemoryError: print('MemoryError') +# expansion of a heap block +try: + l.extend(l2) +except MemoryError: + print('MemoryError') + micropython.heap_unlock() +# check that allocation works after an unlock print([]) diff --git a/tests/micropython/heap_lock.py.exp b/tests/micropython/heap_lock.py.exp index 67b208cfc5..819c326634 100644 --- a/tests/micropython/heap_lock.py.exp +++ b/tests/micropython/heap_lock.py.exp @@ -1,2 +1,3 @@ MemoryError +MemoryError [] diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index a686e71615..d2e557fdcb 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -16,7 +16,6 @@ abc # GC 0 0 -0 # vstr tests sts From 9884a2c712988de8c69a03a5d5be8add043f141e Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Mar 2018 11:01:24 +1100 Subject: [PATCH 386/828] py/objint: Remove unreachable code checking for int type in format func. All callers of mp_obj_int_formatted() are expected to pass in a valid int object, and they do: - mp_obj_int_print() should always pass through an int object because it is the print special method for int instances. - mp_print_mp_int() checks that the argument is an int, and if not converts it to a small int. This patch saves around 20-50 bytes of code space. --- py/objint.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/py/objint.c b/py/objint.c index 59c58f2a61..270e169694 100644 --- a/py/objint.c +++ b/py/objint.c @@ -222,27 +222,26 @@ size_t mp_int_format_size(size_t num_bits, int base, const char *prefix, char co char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in, int base, const char *prefix, char base_char, char comma) { fmt_int_t num; + #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE + // Only have small ints; get the integer value to format. + num = MP_OBJ_SMALL_INT_VALUE(self_in); + #else if (MP_OBJ_IS_SMALL_INT(self_in)) { // A small int; get the integer value to format. num = MP_OBJ_SMALL_INT_VALUE(self_in); -#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE - } else if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) { + } else { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); // Not a small int. -#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG + #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG const mp_obj_int_t *self = self_in; // Get the value to format; mp_obj_get_int truncates to mp_int_t. num = self->val; -#else + #else // Delegate to the implementation for the long int. return mp_obj_int_formatted_impl(buf, buf_size, fmt_size, self_in, base, prefix, base_char, comma); -#endif -#endif - } else { - // Not an int. - **buf = '\0'; - *fmt_size = 0; - return *buf; + #endif } + #endif char sign = '\0'; if (num < 0) { From 1da2d45de6363d4014d379b78f114cd3d1649d7b Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Mar 2018 10:44:38 +1100 Subject: [PATCH 387/828] drivers/bus: Add QSPI abstract type with software QSPI implementation. A new directory drivers/bus/ is introduced, which can hold implementations of bus drivers. A software QSPI implementation is added. --- drivers/bus/qspi.h | 57 ++++++++++++ drivers/bus/softqspi.c | 203 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 260 insertions(+) create mode 100644 drivers/bus/qspi.h create mode 100644 drivers/bus/softqspi.c diff --git a/drivers/bus/qspi.h b/drivers/bus/qspi.h new file mode 100644 index 0000000000..31c9d14fca --- /dev/null +++ b/drivers/bus/qspi.h @@ -0,0 +1,57 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H +#define MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H + +#include "py/mphal.h" + +enum { + MP_QSPI_IOCTL_INIT, + MP_QSPI_IOCTL_DEINIT, + MP_QSPI_IOCTL_BUS_ACQUIRE, + MP_QSPI_IOCTL_BUS_RELEASE, +}; + +typedef struct _mp_qspi_proto_t { + int (*ioctl)(void *self, uint32_t cmd); + void (*write_cmd_data)(void *self, uint8_t cmd, size_t len, uint32_t data); + void (*write_cmd_addr_data)(void *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src); + uint32_t (*read_cmd)(void *self, uint8_t cmd, size_t len); + void (*read_cmd_qaddr_qdata)(void *self, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest); +} mp_qspi_proto_t; + +typedef struct _mp_soft_qspi_obj_t { + mp_hal_pin_obj_t cs; + mp_hal_pin_obj_t clk; + mp_hal_pin_obj_t io0; + mp_hal_pin_obj_t io1; + mp_hal_pin_obj_t io2; + mp_hal_pin_obj_t io3; +} mp_soft_qspi_obj_t; + +extern const mp_qspi_proto_t mp_soft_qspi_proto; + +#endif // MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H diff --git a/drivers/bus/softqspi.c b/drivers/bus/softqspi.c new file mode 100644 index 0000000000..10c5992466 --- /dev/null +++ b/drivers/bus/softqspi.c @@ -0,0 +1,203 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "drivers/bus/qspi.h" + +#define CS_LOW(self) mp_hal_pin_write(self->cs, 0) +#define CS_HIGH(self) mp_hal_pin_write(self->cs, 1) + +#ifdef MICROPY_HW_SOFTQSPI_SCK_LOW + +// Use externally provided functions for SCK control and IO reading +#define SCK_LOW(self) MICROPY_HW_SOFTQSPI_SCK_LOW(self) +#define SCK_HIGH(self) MICROPY_HW_SOFTQSPI_SCK_HIGH(self) +#define NIBBLE_READ(self) MICROPY_HW_SOFTQSPI_NIBBLE_READ(self) + +#else + +// Use generic pin functions for SCK control and IO reading +#define SCK_LOW(self) mp_hal_pin_write(self->clk, 0) +#define SCK_HIGH(self) mp_hal_pin_write(self->clk, 1) +#define NIBBLE_READ(self) ( \ + mp_hal_pin_read(self->io0) \ + | (mp_hal_pin_read(self->io1) << 1) \ + | (mp_hal_pin_read(self->io2) << 2) \ + | (mp_hal_pin_read(self->io3) << 3)) + +#endif + +STATIC void nibble_write(mp_soft_qspi_obj_t *self, uint8_t v) { + mp_hal_pin_write(self->io0, v & 1); + mp_hal_pin_write(self->io1, (v >> 1) & 1); + mp_hal_pin_write(self->io2, (v >> 2) & 1); + mp_hal_pin_write(self->io3, (v >> 3) & 1); +} + +STATIC int mp_soft_qspi_ioctl(void *self_in, uint32_t cmd) { + mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; + + switch (cmd) { + case MP_QSPI_IOCTL_INIT: + mp_hal_pin_high(self->cs); + mp_hal_pin_output(self->cs); + + // Configure pins + mp_hal_pin_write(self->clk, 0); + mp_hal_pin_output(self->clk); + //mp_hal_pin_write(self->clk, 1); + mp_hal_pin_output(self->io0); + mp_hal_pin_input(self->io1); + mp_hal_pin_write(self->io2, 1); + mp_hal_pin_output(self->io2); + mp_hal_pin_write(self->io3, 1); + mp_hal_pin_output(self->io3); + break; + } + + return 0; // success +} + +STATIC void mp_soft_qspi_transfer(mp_soft_qspi_obj_t *self, size_t len, const uint8_t *src, uint8_t *dest) { + // Will run as fast as possible, limited only by CPU speed and GPIO time + mp_hal_pin_input(self->io1); + mp_hal_pin_output(self->io0); + if (self->io3) { + mp_hal_pin_write(self->io2, 1); + mp_hal_pin_output(self->io2); + mp_hal_pin_write(self->io3, 1); + mp_hal_pin_output(self->io3); + } + if (src) { + for (size_t i = 0; i < len; ++i) { + uint8_t data_out = src[i]; + uint8_t data_in = 0; + for (int j = 0; j < 8; ++j, data_out <<= 1) { + mp_hal_pin_write(self->io0, (data_out >> 7) & 1); + mp_hal_pin_write(self->clk, 1); + data_in = (data_in << 1) | mp_hal_pin_read(self->io1); + mp_hal_pin_write(self->clk, 0); + } + if (dest != NULL) { + dest[i] = data_in; + } + } + } else { + for (size_t i = 0; i < len; ++i) { + uint8_t data_in = 0; + for (int j = 0; j < 8; ++j) { + mp_hal_pin_write(self->clk, 1); + data_in = (data_in << 1) | mp_hal_pin_read(self->io1); + mp_hal_pin_write(self->clk, 0); + } + if (dest != NULL) { + dest[i] = data_in; + } + } + } +} + +STATIC void mp_soft_qspi_qread(mp_soft_qspi_obj_t *self, size_t len, uint8_t *buf) { + // Make all IO lines input + mp_hal_pin_input(self->io2); + mp_hal_pin_input(self->io3); + mp_hal_pin_input(self->io0); + mp_hal_pin_input(self->io1); + + // Will run as fast as possible, limited only by CPU speed and GPIO time + while (len--) { + SCK_HIGH(self); + uint8_t data_in = NIBBLE_READ(self); + SCK_LOW(self); + SCK_HIGH(self); + *buf++ = (data_in << 4) | NIBBLE_READ(self); + SCK_LOW(self); + } +} + +STATIC void mp_soft_qspi_qwrite(mp_soft_qspi_obj_t *self, size_t len, const uint8_t *buf) { + // Make all IO lines output + mp_hal_pin_output(self->io2); + mp_hal_pin_output(self->io3); + mp_hal_pin_output(self->io0); + mp_hal_pin_output(self->io1); + + // Will run as fast as possible, limited only by CPU speed and GPIO time + for (size_t i = 0; i < len; ++i) { + nibble_write(self, buf[i] >> 4); + SCK_HIGH(self); + SCK_LOW(self); + + nibble_write(self, buf[i]); + SCK_HIGH(self); + SCK_LOW(self); + } + + //mp_hal_pin_input(self->io1); +} + +STATIC void mp_soft_qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t data) { + mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; + uint32_t cmd_buf = cmd | data << 8; + CS_LOW(self); + mp_soft_qspi_transfer(self, 1 + len, (uint8_t*)&cmd_buf, NULL); + CS_HIGH(self); +} + +STATIC void mp_soft_qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) { + mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; + uint8_t cmd_buf[4] = {cmd, addr >> 16, addr >> 8, addr}; + CS_LOW(self); + mp_soft_qspi_transfer(self, 4, cmd_buf, NULL); + mp_soft_qspi_transfer(self, len, src, NULL); + CS_HIGH(self); +} + +STATIC uint32_t mp_soft_qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) { + mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; + uint32_t cmd_buf = cmd; + CS_LOW(self); + mp_soft_qspi_transfer(self, 1 + len, (uint8_t*)&cmd_buf, (uint8_t*)&cmd_buf); + CS_HIGH(self); + return cmd_buf >> 8; +} + +STATIC void mp_soft_qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) { + mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; + uint8_t cmd_buf[7] = {cmd, addr >> 16, addr >> 8, addr}; + CS_LOW(self); + mp_soft_qspi_transfer(self, 1, cmd_buf, NULL); + mp_soft_qspi_qwrite(self, 6, &cmd_buf[1]); // 3 addr bytes, 1 extra byte (0), 2 dummy bytes (4 dummy cycles) + mp_soft_qspi_qread(self, len, dest); + CS_HIGH(self); +} + +const mp_qspi_proto_t mp_soft_qspi_proto = { + .ioctl = mp_soft_qspi_ioctl, + .write_cmd_data = mp_soft_qspi_write_cmd_data, + .write_cmd_addr_data = mp_soft_qspi_write_cmd_addr_data, + .read_cmd = mp_soft_qspi_read_cmd, + .read_cmd_qaddr_qdata = mp_soft_qspi_read_cmd_qaddr_qdata, +}; From 4e48700f9a284ab73fc199610314f2f6484adbfc Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Mar 2018 16:01:18 +1100 Subject: [PATCH 388/828] drivers/memory/spiflash: Add support for QSPI interface. The spiflash memory driver is reworked to allow the underlying bus to be either normal SPI or QSPI. In both cases the bus can be implemented in software or hardware, as long as the spiflash driver is passed the correct configuration structure. --- drivers/memory/spiflash.c | 413 +++++++++++++++++++++++++++++++------- drivers/memory/spiflash.h | 28 ++- 2 files changed, 361 insertions(+), 80 deletions(-) diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c index 08564d0540..ea0fef8052 100644 --- a/drivers/memory/spiflash.c +++ b/drivers/memory/spiflash.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2016-2017 Damien P. George + * Copyright (c) 2016-2018 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,57 +29,117 @@ #include "py/mperrno.h" #include "py/mphal.h" -#include "extmod/machine_spi.h" #include "drivers/memory/spiflash.h" -#define CMD_WRITE (0x02) -#define CMD_READ (0x03) -#define CMD_WRDI (0x04) -#define CMD_RDSR (0x05) -#define CMD_WREN (0x06) -#define CMD_SEC_ERASE (0x20) +#define QSPI_QE_MASK (0x02) +#define USE_WR_DELAY (1) + +#define CMD_WRSR (0x01) +#define CMD_WRITE (0x02) +#define CMD_READ (0x03) +#define CMD_RDSR (0x05) +#define CMD_WREN (0x06) +#define CMD_SEC_ERASE (0x20) +#define CMD_RDCR (0x35) +#define CMD_RD_DEVID (0x9f) +#define CMD_CHIP_ERASE (0xc7) +#define CMD_C4READ (0xeb) + #define WAIT_SR_TIMEOUT (1000000) #define PAGE_SIZE (256) // maximum bytes we can write in one SPI transfer #define SECTOR_SIZE (4096) // size of erase sector // Note: this code is not reentrant with this shared buffer -STATIC uint8_t buf[SECTOR_SIZE]; - -void mp_spiflash_init(mp_spiflash_t *self) { - mp_hal_pin_write(self->cs, 1); - mp_hal_pin_output(self->cs); - const mp_machine_spi_p_t *protocol = self->spi->type->protocol; - protocol->init(self->spi, 0, NULL, (mp_map_t*)&mp_const_empty_map); -} +STATIC uint8_t buf[SECTOR_SIZE] __attribute__((aligned(4))); +STATIC mp_spiflash_t *bufuser; // current user of buf +STATIC uint32_t bufsec; // current sector stored in buf; 0xffffffff if invalid STATIC void mp_spiflash_acquire_bus(mp_spiflash_t *self) { - // can be used for actions needed to acquire bus - (void)self; + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_QSPI) { + c->bus.u_qspi.proto->ioctl(c->bus.u_qspi.data, MP_QSPI_IOCTL_BUS_ACQUIRE); + } } STATIC void mp_spiflash_release_bus(mp_spiflash_t *self) { - // can be used for actions needed to release bus - (void)self; + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_QSPI) { + c->bus.u_qspi.proto->ioctl(c->bus.u_qspi.data, MP_QSPI_IOCTL_BUS_RELEASE); + } } -STATIC void mp_spiflash_transfer(mp_spiflash_t *self, size_t len, const uint8_t *src, uint8_t *dest) { - const mp_machine_spi_p_t *protocol = self->spi->type->protocol; - protocol->transfer(self->spi, len, src, dest); +STATIC void mp_spiflash_write_cmd_data(mp_spiflash_t *self, uint8_t cmd, size_t len, uint32_t data) { + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_SPI) { + // Note: len/data are unused for standard SPI + mp_hal_pin_write(c->bus.u_spi.cs, 0); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 1, &cmd, NULL); + mp_hal_pin_write(c->bus.u_spi.cs, 1); + } else { + c->bus.u_qspi.proto->write_cmd_data(c->bus.u_qspi.data, cmd, len, data); + } +} + +STATIC void mp_spiflash_write_cmd_addr_data(mp_spiflash_t *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) { + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_SPI) { + uint8_t buf[4] = {cmd, addr >> 16, addr >> 8, addr}; + mp_hal_pin_write(c->bus.u_spi.cs, 0); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 4, buf, NULL); + if (len) { + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, src, NULL); + } + mp_hal_pin_write(c->bus.u_spi.cs, 1); + } else { + c->bus.u_qspi.proto->write_cmd_addr_data(c->bus.u_qspi.data, cmd, addr, len, src); + } +} + +STATIC uint32_t mp_spiflash_read_cmd(mp_spiflash_t *self, uint8_t cmd, size_t len) { + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_SPI) { + uint32_t buf; + mp_hal_pin_write(c->bus.u_spi.cs, 0); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 1, &cmd, NULL); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, (void*)&buf, (void*)&buf); + mp_hal_pin_write(c->bus.u_spi.cs, 1); + return buf; + } else { + return c->bus.u_qspi.proto->read_cmd(c->bus.u_qspi.data, cmd, len); + } +} + +STATIC void mp_spiflash_read_data(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) { + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_SPI) { + uint8_t buf[4] = {CMD_READ, addr >> 16, addr >> 8, addr}; + mp_hal_pin_write(c->bus.u_spi.cs, 0); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 4, buf, NULL); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, dest, dest); + mp_hal_pin_write(c->bus.u_spi.cs, 1); + } else { + c->bus.u_qspi.proto->read_cmd_qaddr_qdata(c->bus.u_qspi.data, CMD_C4READ, addr, len, dest); + } +} + +STATIC void mp_spiflash_write_cmd(mp_spiflash_t *self, uint8_t cmd) { + mp_spiflash_write_cmd_data(self, cmd, 0, 0); +} + +STATIC void mp_spiflash_write_cmd_addr(mp_spiflash_t *self, uint8_t cmd, uint32_t addr) { + mp_spiflash_write_cmd_addr_data(self, cmd, addr, 0, NULL); } STATIC int mp_spiflash_wait_sr(mp_spiflash_t *self, uint8_t mask, uint8_t val, uint32_t timeout) { - uint8_t cmd[1] = {CMD_RDSR}; - mp_hal_pin_write(self->cs, 0); - mp_spiflash_transfer(self, 1, cmd, NULL); + uint8_t sr; for (; timeout; --timeout) { - mp_spiflash_transfer(self, 1, cmd, cmd); - if ((cmd[0] & mask) == val) { + sr = mp_spiflash_read_cmd(self, CMD_RDSR, 1); + if ((sr & mask) == val) { break; } } - mp_hal_pin_write(self->cs, 1); - if ((cmd[0] & mask) == val) { + if ((sr & mask) == val) { return 0; // success } else if (timeout == 0) { return -MP_ETIMEDOUT; @@ -96,10 +156,40 @@ STATIC int mp_spiflash_wait_wip0(mp_spiflash_t *self) { return mp_spiflash_wait_sr(self, 1, 0, WAIT_SR_TIMEOUT); } -STATIC void mp_spiflash_write_cmd(mp_spiflash_t *self, uint8_t cmd) { - mp_hal_pin_write(self->cs, 0); - mp_spiflash_transfer(self, 1, &cmd, NULL); - mp_hal_pin_write(self->cs, 1); +void mp_spiflash_init(mp_spiflash_t *self) { + self->flags = 0; + + if (self->config->bus_kind == MP_SPIFLASH_BUS_SPI) { + mp_hal_pin_write(self->config->bus.u_spi.cs, 1); + mp_hal_pin_output(self->config->bus.u_spi.cs); + self->config->bus.u_spi.proto->init(self->config->bus.u_spi.data, 0, NULL, (mp_map_t*)&mp_const_empty_map); + } else { + self->config->bus.u_qspi.proto->ioctl(self->config->bus.u_qspi.data, MP_QSPI_IOCTL_INIT); + } + + mp_spiflash_acquire_bus(self); + + #if defined(CHECK_DEVID) + // Validate device id + uint32_t devid = mp_spiflash_read_cmd(self, CMD_RD_DEVID, 3); + if (devid != CHECK_DEVID) { + return 0; + } + #endif + + if (self->config->bus_kind == MP_SPIFLASH_BUS_QSPI) { + // Set QE bit + uint32_t data = (mp_spiflash_read_cmd(self, CMD_RDSR, 1) & 0xff) + | (mp_spiflash_read_cmd(self, CMD_RDCR, 1) & 0xff) << 8; + if (!(data & (QSPI_QE_MASK << 16))) { + data |= QSPI_QE_MASK << 16; + mp_spiflash_write_cmd(self, CMD_WREN); + mp_spiflash_write_cmd_data(self, CMD_WRSR, 2, data); + mp_spiflash_wait_wip0(self); + } + } + + mp_spiflash_release_bus(self); } STATIC int mp_spiflash_erase_sector(mp_spiflash_t *self, uint32_t addr) { @@ -113,10 +203,7 @@ STATIC int mp_spiflash_erase_sector(mp_spiflash_t *self, uint32_t addr) { } // erase the sector - mp_hal_pin_write(self->cs, 0); - uint8_t cmd[4] = {CMD_SEC_ERASE, addr >> 16, addr >> 8, addr}; - mp_spiflash_transfer(self, 4, cmd, NULL); - mp_hal_pin_write(self->cs, 1); + mp_spiflash_write_cmd_addr(self, CMD_SEC_ERASE, addr); // wait WIP=0 return mp_spiflash_wait_wip0(self); @@ -133,67 +220,239 @@ STATIC int mp_spiflash_write_page(mp_spiflash_t *self, uint32_t addr, const uint } // write the page - mp_hal_pin_write(self->cs, 0); - uint8_t cmd[4] = {CMD_WRITE, addr >> 16, addr >> 8, addr}; - mp_spiflash_transfer(self, 4, cmd, NULL); - mp_spiflash_transfer(self, PAGE_SIZE, src, NULL); - mp_hal_pin_write(self->cs, 1); + mp_spiflash_write_cmd_addr_data(self, CMD_WRITE, addr, PAGE_SIZE, src); // wait WIP=0 return mp_spiflash_wait_wip0(self); } void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) { + if (len == 0) { + return; + } mp_spiflash_acquire_bus(self); - uint8_t cmd[4] = {CMD_READ, addr >> 16, addr >> 8, addr}; - mp_hal_pin_write(self->cs, 0); - mp_spiflash_transfer(self, 4, cmd, NULL); - mp_spiflash_transfer(self, len, dest, dest); - mp_hal_pin_write(self->cs, 1); + if (bufuser == self && bufsec != 0xffffffff) { + uint32_t bis = addr / SECTOR_SIZE; + int rest = 0; + if (bis < bufsec) { + rest = bufsec * SECTOR_SIZE - addr; + if (rest > len) { + rest = len; + } + mp_spiflash_read_data(self, addr, rest, dest); + len -= rest; + if (len <= 0) { + mp_spiflash_release_bus(self); + return; + } else { + // Something from buffer... + addr = bufsec * SECTOR_SIZE; + dest += rest; + if (len > SECTOR_SIZE) { + rest = SECTOR_SIZE; + } else { + rest = len; + } + memcpy(dest, buf, rest); + len -= rest; + if (len <= 0) { + mp_spiflash_release_bus(self); + return; + } + dest += rest; + addr += rest; + } + } else if (bis == bufsec) { + uint32_t offset = addr & (SECTOR_SIZE-1); + rest = SECTOR_SIZE - offset; + if (rest > len) { + rest = len; + } + memcpy(dest, &buf[offset], rest); + len -= rest; + if (len <= 0) { + mp_spiflash_release_bus(self); + return; + } + } + dest += rest; + addr += rest; + } + // Read rest direct from flash + mp_spiflash_read_data(self, addr, len, dest); mp_spiflash_release_bus(self); } -int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { - // TODO optimise so we don't need to erase multiple times for successive writes to a sector +STATIC void mp_spiflash_flush_internal(mp_spiflash_t *self) { + #if USE_WR_DELAY + if (!(self->flags & 1)) { + return; + } - // align to 4096 sector + self->flags &= ~1; + + // Erase sector + int ret = mp_spiflash_erase_sector(self, bufsec * SECTOR_SIZE); + if (ret != 0) { + return; + } + + // Write + for (int i = 0; i < 16; i += 1) { + int ret = mp_spiflash_write_page(self, bufsec * SECTOR_SIZE + i * PAGE_SIZE, buf + i * PAGE_SIZE); + if (ret != 0) { + return; + } + } + #endif +} + +void mp_spiflash_flush(mp_spiflash_t *self) { + mp_spiflash_acquire_bus(self); + mp_spiflash_flush_internal(self); + mp_spiflash_release_bus(self); +} + +STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { + // Align to 4096 sector uint32_t offset = addr & 0xfff; - addr = (addr >> 12) << 12; + uint32_t sec = addr >> 12; + addr = sec << 12; - // restriction for now, so we don't need to erase multiple pages + // Restriction for now, so we don't need to erase multiple pages if (offset + len > sizeof(buf)) { - printf("mp_spiflash_write: len is too large\n"); + printf("mp_spiflash_write_part: len is too large\n"); return -MP_EIO; } - mp_spiflash_acquire_bus(self); - - // read sector - uint8_t cmd[4] = {CMD_READ, addr >> 16, addr >> 8, addr}; - mp_hal_pin_write(self->cs, 0); - mp_spiflash_transfer(self, 4, cmd, NULL); - mp_spiflash_transfer(self, SECTOR_SIZE, buf, buf); - mp_hal_pin_write(self->cs, 1); - - // erase sector - int ret = mp_spiflash_erase_sector(self, addr); - if (ret != 0) { - mp_spiflash_release_bus(self); - return ret; + // Acquire the sector buffer + if (bufuser != self) { + if (bufuser != NULL) { + mp_spiflash_flush(bufuser); + } + bufuser = self; + bufsec = 0xffffffff; } - // copy new block into buffer - memcpy(buf + offset, src, len); + if (bufsec != sec) { + // Read sector + #if USE_WR_DELAY + if (bufsec != 0xffffffff) { + mp_spiflash_flush_internal(self); + } + #endif + mp_spiflash_read_data(self, addr, SECTOR_SIZE, buf); + } - // write sector in pages of 256 bytes - for (int i = 0; i < SECTOR_SIZE; i += 256) { - ret = mp_spiflash_write_page(self, addr + i, buf + i); - if (ret != 0) { - mp_spiflash_release_bus(self); - return ret; + #if USE_WR_DELAY + + bufsec = sec; + // Just copy to buffer + memcpy(buf + offset, src, len); + // And mark dirty + self->flags |= 1; + + #else + + uint32_t dirty = 0; + for (size_t i = 0; i < len; ++i) { + if (buf[offset + i] != src[i]) { + if (buf[offset + i] != 0xff) { + // Erase sector + int ret = mp_spiflash_erase_sector(self, addr); + if (ret != 0) { + return ret; + } + dirty = 0xffff; + break; + } else { + dirty |= (1 << ((offset + i) >> 8)); + } } } - mp_spiflash_release_bus(self); + bufsec = sec; + // Copy new block into buffer + memcpy(buf + offset, src, len); + + // Write sector in pages of 256 bytes + for (size_t i = 0; i < 16; ++i) { + if (dirty & (1 << i)) { + int ret = mp_spiflash_write_page(self, addr + i * PAGE_SIZE, buf + i * PAGE_SIZE); + if (ret != 0) { + return ret; + } + } + } + + #endif + return 0; // success } + +int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { + uint32_t bis = addr / SECTOR_SIZE; + uint32_t bie = (addr + len - 1) / SECTOR_SIZE; + + mp_spiflash_acquire_bus(self); + if (bufuser == self && bis <= bufsec && bie >= bufsec) { + // Current buffer affected, handle this part first + uint32_t taddr = (bufsec + 1) * SECTOR_SIZE; + int32_t offset = addr - bufsec * SECTOR_SIZE; + int32_t pre = bufsec * SECTOR_SIZE - addr; + if (offset < 0) { + offset = 0; + } else { + pre = 0; + } + int32_t rest = len - pre; + int32_t trail = 0; + if (rest > SECTOR_SIZE - offset) { + trail = rest - (SECTOR_SIZE - offset); + rest = SECTOR_SIZE - offset; + } + memcpy(&buf[offset], &src[pre], rest); + self->flags |= 1; // Mark dirty + if ((pre | trail) == 0) { + mp_spiflash_release_bus(self); + return 0; + } + const uint8_t *p = src; + while (pre) { + int rest = pre & (SECTOR_SIZE - 1); + if (rest == 0) { + rest = SECTOR_SIZE; + } + mp_spiflash_write_part(self, addr, rest, p); + p += rest; + addr += rest; + pre -= rest; + } + while (trail) { + int rest = trail; + if (rest > SECTOR_SIZE) { + rest = SECTOR_SIZE; + } + mp_spiflash_write_part(self, taddr, rest, src); + src += rest; + taddr += rest; + trail -= rest; + } + } else { + // Current buffer not affected, business as usual + uint32_t offset = addr & (SECTOR_SIZE - 1); + while (len) { + int rest = SECTOR_SIZE - offset; + if (rest > len) { + rest = len; + } + mp_spiflash_write_part(self, addr, rest, src); + len -= rest; + addr += rest; + src += rest; + offset = 0; + } + } + mp_spiflash_release_bus(self); + return 0; +} diff --git a/drivers/memory/spiflash.h b/drivers/memory/spiflash.h index cd96b16f34..79ba5490b1 100644 --- a/drivers/memory/spiflash.h +++ b/drivers/memory/spiflash.h @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2016 Damien P. George + * Copyright (c) 2016-2018 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,14 +26,36 @@ #ifndef MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H #define MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H +#include "drivers/bus/qspi.h" #include "extmod/machine_spi.h" +enum { + MP_SPIFLASH_BUS_SPI, + MP_SPIFLASH_BUS_QSPI, +}; + +typedef struct _mp_spiflash_config_t { + uint32_t bus_kind; + union { + struct { + mp_hal_pin_obj_t cs; + void *data; + const mp_machine_spi_p_t *proto; + } u_spi; + struct { + void *data; + const mp_qspi_proto_t *proto; + } u_qspi; + } bus; +} mp_spiflash_config_t; + typedef struct _mp_spiflash_t { - mp_hal_pin_obj_t cs; - mp_obj_base_t *spi; // object must have protocol pointing to mp_machine_spi_p_t struct + const mp_spiflash_config_t *config; + volatile uint32_t flags; } mp_spiflash_t; void mp_spiflash_init(mp_spiflash_t *self); +void mp_spiflash_flush(mp_spiflash_t *self); void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest); int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src); From 21d5527edf37ba550316ea0dbac87253c7791bd1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Mar 2018 19:12:52 +1100 Subject: [PATCH 389/828] extmod/machine_spi: Make SPI protocol structure public. So it can be referenced directly without the need for the uPy object. --- extmod/machine_spi.c | 2 +- extmod/machine_spi.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/extmod/machine_spi.c b/extmod/machine_spi.c index a67d294baf..cfd94fcef7 100644 --- a/extmod/machine_spi.c +++ b/extmod/machine_spi.c @@ -321,7 +321,7 @@ STATIC void mp_machine_soft_spi_init(mp_obj_base_t *self_in, size_t n_args, cons mp_hal_pin_input(self->miso); } -STATIC const mp_machine_spi_p_t mp_machine_soft_spi_p = { +const mp_machine_spi_p_t mp_machine_soft_spi_p = { .init = mp_machine_soft_spi_init, .deinit = NULL, .transfer = mp_machine_soft_spi_transfer, diff --git a/extmod/machine_spi.h b/extmod/machine_spi.h index e24e41eb3d..3ee1b241f0 100644 --- a/extmod/machine_spi.h +++ b/extmod/machine_spi.h @@ -46,6 +46,7 @@ typedef struct _mp_machine_soft_spi_obj_t { mp_hal_pin_obj_t miso; } mp_machine_soft_spi_obj_t; +extern const mp_machine_spi_p_t mp_machine_soft_spi_p; extern const mp_obj_type_t mp_machine_soft_spi_type; extern const mp_obj_dict_t mp_machine_spi_locals_dict; From a0dfc386410b3a397e8643b269e352a8930b5f53 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Mar 2018 23:11:47 +1100 Subject: [PATCH 390/828] stm32/spibdev: Update to work with new spiflash driver. --- ports/stm32/spibdev.c | 49 ++++++++++++++++++++++++++++++++----------- ports/stm32/storage.c | 2 ++ ports/stm32/storage.h | 2 ++ 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/ports/stm32/spibdev.c b/ports/stm32/spibdev.c index 5e5123867d..e70507b7ba 100644 --- a/ports/stm32/spibdev.c +++ b/ports/stm32/spibdev.c @@ -25,6 +25,8 @@ */ #include "py/obj.h" +#include "systick.h" +#include "led.h" #include "storage.h" #if defined(MICROPY_HW_SPIFLASH_SIZE_BITS) @@ -32,6 +34,8 @@ #include "drivers/memory/spiflash.h" #include "genhdr/pins.h" +static uint32_t flash_tick_counter_last_write; + STATIC const mp_machine_soft_spi_obj_t spiflash_spi_bus = { .base = {&mp_machine_soft_spi_type}, .delay_half = MICROPY_PY_MACHINE_SPI_MIN_DELAY, @@ -42,22 +46,42 @@ STATIC const mp_machine_soft_spi_obj_t spiflash_spi_bus = { .miso = &MICROPY_HW_SPIFLASH_MISO, }; -STATIC const mp_spiflash_t spiflash = { - .cs = &MICROPY_HW_SPIFLASH_CS, - .spi = (mp_obj_base_t*)&spiflash_spi_bus.base, +STATIC const mp_spiflash_config_t spiflash_config = { + .bus_kind = MP_SPIFLASH_BUS_SPI, + .bus.u_spi.cs = &MICROPY_HW_SPIFLASH_CS, + .bus.u_spi.data = (void*)&spiflash_spi_bus, + .bus.u_spi.proto = &mp_machine_soft_spi_p, }; +STATIC mp_spiflash_t spiflash; + void spi_bdev_init(void) { - mp_spiflash_init((mp_spiflash_t*)&spiflash); + spiflash.config = &spiflash_config; + mp_spiflash_init(&spiflash); + flash_tick_counter_last_write = 0; +} + +void spi_bdev_irq_handler(void) { + if ((spiflash.flags & 1) && sys_tick_has_passed(flash_tick_counter_last_write, 1000)) { + mp_spiflash_flush(&spiflash); + led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off + } +} + +void spi_bdev_flush(void) { + if (spiflash.flags & 1) { + // we must disable USB irqs to prevent MSC contention with SPI flash + uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); + mp_spiflash_flush(&spiflash); + led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off + restore_irq_pri(basepri); + } } bool spi_bdev_readblock(uint8_t *dest, uint32_t block) { // we must disable USB irqs to prevent MSC contention with SPI flash uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - - mp_spiflash_read((mp_spiflash_t*)&spiflash, - block * FLASH_BLOCK_SIZE, FLASH_BLOCK_SIZE, dest); - + mp_spiflash_read(&spiflash, block * FLASH_BLOCK_SIZE, FLASH_BLOCK_SIZE, dest); restore_irq_pri(basepri); return true; @@ -66,10 +90,11 @@ bool spi_bdev_readblock(uint8_t *dest, uint32_t block) { bool spi_bdev_writeblock(const uint8_t *src, uint32_t block) { // we must disable USB irqs to prevent MSC contention with SPI flash uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - - int ret = mp_spiflash_write((mp_spiflash_t*)&spiflash, - block * FLASH_BLOCK_SIZE, FLASH_BLOCK_SIZE, src); - + int ret = mp_spiflash_write(&spiflash, block * FLASH_BLOCK_SIZE, FLASH_BLOCK_SIZE, src); + if (spiflash.flags & 1) { + led_state(PYB_LED_RED, 1); // indicate a dirty cache with LED on + flash_tick_counter_last_write = HAL_GetTick(); + } restore_irq_pri(basepri); return ret == 0; diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index 5eab4c7022..0607aeb88c 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -39,6 +39,8 @@ // Use external SPI flash as the storage medium #define BDEV_NUM_BLOCKS (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) #define BDEV_INIT spi_bdev_init +#define BDEV_IRQ_HANDLER spi_bdev_irq_handler +#define BDEV_FLUSH spi_bdev_flush #define BDEV_READBLOCK spi_bdev_readblock #define BDEV_WRITEBLOCK spi_bdev_writeblock diff --git a/ports/stm32/storage.h b/ports/stm32/storage.h index 37cacc1a68..2497633896 100644 --- a/ports/stm32/storage.h +++ b/ports/stm32/storage.h @@ -51,6 +51,8 @@ bool flash_bdev_readblock(uint8_t *dest, uint32_t block); bool flash_bdev_writeblock(const uint8_t *src, uint32_t block); void spi_bdev_init(void); +void spi_bdev_irq_handler(void); +void spi_bdev_flush(void); bool spi_bdev_readblock(uint8_t *dest, uint32_t block); bool spi_bdev_writeblock(const uint8_t *src, uint32_t block); From 0210383da5804976d9282247d7c308664dc2e6f6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Mar 2018 23:49:00 +1100 Subject: [PATCH 391/828] stm32/spibdev: Add option to configure SPI block dev to use QSPI flash. To use QSPI (in software QSPI mode) the configuration needed is: #define MICROPY_HW_SPIFLASH_SIZE_BITS (n * 1024 * 1024) #define MICROPY_HW_SPIFLASH_CS (pin_x1) #define MICROPY_HW_SPIFLASH_SCK (pin_x2) #define MICROPY_HW_SPIFLASH_IO0 (pin_x3) #define MICROPY_HW_SPIFLASH_IO1 (pin_x4) #define MICROPY_HW_SPIFLASH_IO2 (pin_x5) #define MICROPY_HW_SPIFLASH_IO3 (pin_x6) --- ports/stm32/Makefile | 1 + ports/stm32/spibdev.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 854820abe3..18e64899b5 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -185,6 +185,7 @@ EXTMOD_SRC_C = $(addprefix extmod/,\ ) DRIVERS_SRC_C = $(addprefix drivers/,\ + bus/softqspi.c \ memory/spiflash.c \ dht/dht.c \ ) diff --git a/ports/stm32/spibdev.c b/ports/stm32/spibdev.c index e70507b7ba..4481a7a709 100644 --- a/ports/stm32/spibdev.c +++ b/ports/stm32/spibdev.c @@ -36,6 +36,10 @@ static uint32_t flash_tick_counter_last_write; +#if defined(MICROPY_HW_SPIFLASH_MOSI) + +// External SPI flash uses standard SPI interface + STATIC const mp_machine_soft_spi_obj_t spiflash_spi_bus = { .base = {&mp_machine_soft_spi_type}, .delay_half = MICROPY_PY_MACHINE_SPI_MIN_DELAY, @@ -53,6 +57,29 @@ STATIC const mp_spiflash_config_t spiflash_config = { .bus.u_spi.proto = &mp_machine_soft_spi_p, }; +#elif defined(MICROPY_HW_SPIFLASH_IO0) + +// External SPI flash uses quad SPI interface + +#include "drivers/bus/qspi.h" + +STATIC const mp_soft_qspi_obj_t soft_qspi_bus = { + .cs = &MICROPY_HW_SPIFLASH_CS, + .clk = &MICROPY_HW_SPIFLASH_SCK, + .io0 = &MICROPY_HW_SPIFLASH_IO0, + .io1 = &MICROPY_HW_SPIFLASH_IO1, + .io2 = &MICROPY_HW_SPIFLASH_IO2, + .io3 = &MICROPY_HW_SPIFLASH_IO3, +}; + +STATIC const mp_spiflash_config_t spiflash_config = { + .bus_kind = MP_SPIFLASH_BUS_QSPI, + .bus.u_qspi.data = (void*)&soft_qspi_bus, + .bus.u_qspi.proto = &mp_soft_qspi_proto, +}; + +#endif + STATIC mp_spiflash_t spiflash; void spi_bdev_init(void) { From 861080aa3d595f9b9cbfeca80c56da9785eca430 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Mar 2018 23:51:06 +1100 Subject: [PATCH 392/828] stm32/storage: Add option for bdev to supply readblock/writeblocks. If the underlying block device supports it, it's more efficient to read/write multiple blocks at once. --- ports/stm32/storage.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index 0607aeb88c..0b6f2db621 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -151,8 +151,10 @@ bool storage_read_block(uint8_t *dest, uint32_t block) { return true; + #if defined(BDEV_READBLOCK) } else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + BDEV_NUM_BLOCKS) { return BDEV_READBLOCK(dest, block - FLASH_PART1_START_BLOCK); + #endif } else { return false; } @@ -163,14 +165,22 @@ bool storage_write_block(const uint8_t *src, uint32_t block) { if (block == 0) { // can't write MBR, but pretend we did return true; + #if defined(BDEV_WRITEBLOCK) } else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + BDEV_NUM_BLOCKS) { return BDEV_WRITEBLOCK(src, block - FLASH_PART1_START_BLOCK); + #endif } else { return false; } } mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { + #if defined(BDEV_READBLOCKS) + if (FLASH_PART1_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART1_START_BLOCK + BDEV_NUM_BLOCKS) { + return BDEV_READBLOCKS(dest, block_num - FLASH_PART1_START_BLOCK, num_blocks); + } + #endif + for (size_t i = 0; i < num_blocks; i++) { if (!storage_read_block(dest + i * FLASH_BLOCK_SIZE, block_num + i)) { return 1; // error @@ -180,6 +190,12 @@ mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_bl } mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { + #if defined(BDEV_WRITEBLOCKS) + if (FLASH_PART1_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART1_START_BLOCK + BDEV_NUM_BLOCKS) { + return BDEV_WRITEBLOCKS(src, block_num - FLASH_PART1_START_BLOCK, num_blocks); + } + #endif + for (size_t i = 0; i < num_blocks; i++) { if (!storage_write_block(src + i * FLASH_BLOCK_SIZE, block_num + i)) { return 1; // error From 8bd0a51ca9e5106a834b5db070855932a0b042df Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 3 Mar 2018 00:13:15 +1100 Subject: [PATCH 393/828] stm32/spibdev: Convert to use multiple block read/write interface. The spiflash driver now supports read/write of multiple blocks at a time. --- ports/stm32/spibdev.c | 12 ++++++------ ports/stm32/storage.c | 4 ++-- ports/stm32/storage.h | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ports/stm32/spibdev.c b/ports/stm32/spibdev.c index 4481a7a709..3eadb995d6 100644 --- a/ports/stm32/spibdev.c +++ b/ports/stm32/spibdev.c @@ -105,26 +105,26 @@ void spi_bdev_flush(void) { } } -bool spi_bdev_readblock(uint8_t *dest, uint32_t block) { +int spi_bdev_readblocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { // we must disable USB irqs to prevent MSC contention with SPI flash uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - mp_spiflash_read(&spiflash, block * FLASH_BLOCK_SIZE, FLASH_BLOCK_SIZE, dest); + mp_spiflash_read(&spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, dest); restore_irq_pri(basepri); - return true; + return 0; } -bool spi_bdev_writeblock(const uint8_t *src, uint32_t block) { +int spi_bdev_writeblocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { // we must disable USB irqs to prevent MSC contention with SPI flash uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - int ret = mp_spiflash_write(&spiflash, block * FLASH_BLOCK_SIZE, FLASH_BLOCK_SIZE, src); + int ret = mp_spiflash_write(&spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, src); if (spiflash.flags & 1) { led_state(PYB_LED_RED, 1); // indicate a dirty cache with LED on flash_tick_counter_last_write = HAL_GetTick(); } restore_irq_pri(basepri); - return ret == 0; + return ret; } #endif // defined(MICROPY_HW_SPIFLASH_SIZE_BITS) diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index 0b6f2db621..46bd4fdc76 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -41,8 +41,8 @@ #define BDEV_INIT spi_bdev_init #define BDEV_IRQ_HANDLER spi_bdev_irq_handler #define BDEV_FLUSH spi_bdev_flush -#define BDEV_READBLOCK spi_bdev_readblock -#define BDEV_WRITEBLOCK spi_bdev_writeblock +#define BDEV_READBLOCKS spi_bdev_readblocks +#define BDEV_WRITEBLOCKS spi_bdev_writeblocks #else diff --git a/ports/stm32/storage.h b/ports/stm32/storage.h index 2497633896..8b3cedb127 100644 --- a/ports/stm32/storage.h +++ b/ports/stm32/storage.h @@ -53,8 +53,8 @@ bool flash_bdev_writeblock(const uint8_t *src, uint32_t block); void spi_bdev_init(void); void spi_bdev_irq_handler(void); void spi_bdev_flush(void); -bool spi_bdev_readblock(uint8_t *dest, uint32_t block); -bool spi_bdev_writeblock(const uint8_t *src, uint32_t block); +int spi_bdev_readblocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks); +int spi_bdev_writeblocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks); extern const struct _mp_obj_type_t pyb_flash_type; From adda38cf7670bd4512de9e9a4c19fbc679433bdc Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 3 Mar 2018 00:17:08 +1100 Subject: [PATCH 394/828] stm32/qspi: Add hardware QSPI driver, with memory-map capability. It supports the abstract QSPI protocol defined in drivers/bus/qspi.h. --- ports/stm32/Makefile | 1 + ports/stm32/qspi.c | 248 +++++++++++++++++++++++++++++++++++++++++++ ports/stm32/qspi.h | 36 +++++++ 3 files changed, 285 insertions(+) create mode 100644 ports/stm32/qspi.c create mode 100644 ports/stm32/qspi.h diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 18e64899b5..0f836f2455 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -214,6 +214,7 @@ SRC_C = \ dma.c \ i2c.c \ spi.c \ + qspi.c \ uart.c \ can.c \ usb.c \ diff --git a/ports/stm32/qspi.c b/ports/stm32/qspi.c new file mode 100644 index 0000000000..e1ba38c619 --- /dev/null +++ b/ports/stm32/qspi.c @@ -0,0 +1,248 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/mperrno.h" +#include "py/mphal.h" +#include "genhdr/pins.h" +#include "qspi.h" + +#if defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2) + +void qspi_init(void) { + // Configure pins + mp_hal_pin_config(&MICROPY_HW_QSPIFLASH_CS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 10); + mp_hal_pin_config(&MICROPY_HW_QSPIFLASH_SCK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); + mp_hal_pin_config(&MICROPY_HW_QSPIFLASH_IO0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); + mp_hal_pin_config(&MICROPY_HW_QSPIFLASH_IO1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); + mp_hal_pin_config(&MICROPY_HW_QSPIFLASH_IO2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); + mp_hal_pin_config(&MICROPY_HW_QSPIFLASH_IO3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); + + // Bring up the QSPI peripheral + + __HAL_RCC_QSPI_CLK_ENABLE(); + + QUADSPI->CR = + 2 << QUADSPI_CR_PRESCALER_Pos // F_CLK = F_AHB/3 (72MHz when CPU is 216MHz) + #if defined(QUADSPI_CR_FSEL_Pos) + | 0 << QUADSPI_CR_FSEL_Pos // FLASH 1 selected + #endif + #if defined(QUADSPI_CR_DFM_Pos) + | 0 << QUADSPI_CR_DFM_Pos // dual-flash mode disabled + #endif + | 0 << QUADSPI_CR_SSHIFT_Pos // no sample shift + | 1 << QUADSPI_CR_TCEN_Pos // timeout counter enabled + | 1 << QUADSPI_CR_EN_Pos // enable the peripheral + ; + + QUADSPI->DCR = + (MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 - 3 - 1) << QUADSPI_DCR_FSIZE_Pos + | 1 << QUADSPI_DCR_CSHT_Pos // nCS stays high for 2 cycles + | 0 << QUADSPI_DCR_CKMODE_Pos // CLK idles at low state + ; +} + +void qspi_memory_map(void) { + // Enable memory-mapped mode + + QUADSPI->ABR = 0; // disable continuous read mode + QUADSPI->LPTR = 100; // to tune + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 3 << QUADSPI_CCR_FMODE_Pos // memory-mapped mode + | 3 << QUADSPI_CCR_DMODE_Pos // data on 4 lines + | 4 << QUADSPI_CCR_DCYC_Pos // 4 dummy cycles + | 0 << QUADSPI_CCR_ABSIZE_Pos // 8-bit alternate byte + | 3 << QUADSPI_CCR_ABMODE_Pos // alternate byte on 4 lines + | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size + | 3 << QUADSPI_CCR_ADMODE_Pos // address on 4 lines + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | 0xeb << QUADSPI_CCR_INSTRUCTION_Pos // quad read opcode + ; +} + +STATIC int qspi_ioctl(void *self_in, uint32_t cmd) { + (void)self_in; + switch (cmd) { + case MP_QSPI_IOCTL_INIT: + qspi_init(); + break; + case MP_QSPI_IOCTL_BUS_RELEASE: + // Switch to memory-map mode when bus is idle + qspi_memory_map(); + break; + } + return 0; // success +} + +STATIC void qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t data) { + (void)self_in; + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag + + if (len == 0) { + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode + | 0 << QUADSPI_CCR_DMODE_Pos // no data + | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles + | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte + | 0 << QUADSPI_CCR_ADMODE_Pos // no address + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode + ; + } else { + QUADSPI->DLR = len - 1; + + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode + | 1 << QUADSPI_CCR_DMODE_Pos // data on 1 line + | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles + | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte + | 0 << QUADSPI_CCR_ADMODE_Pos // no address + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode + ; + + // This assumes len==2 + *(uint16_t*)&QUADSPI->DR = data; + } + + // Wait for write to finish + while (!(QUADSPI->SR & QUADSPI_SR_TCF)) { + } + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag +} + +STATIC void qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) { + (void)self_in; + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag + + if (len == 0) { + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode + | 0 << QUADSPI_CCR_DMODE_Pos // no data + | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles + | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte + | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size + | 1 << QUADSPI_CCR_ADMODE_Pos // address on 1 line + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode + ; + + QUADSPI->AR = addr; + } else { + QUADSPI->DLR = len - 1; + + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode + | 1 << QUADSPI_CCR_DMODE_Pos // data on 1 line + | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles + | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte + | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size + | 1 << QUADSPI_CCR_ADMODE_Pos // address on 1 line + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode + ; + + QUADSPI->AR = addr; + + // Write out the data + while (len) { + while (!(QUADSPI->SR & QUADSPI_SR_FTF)) { + } + // TODO it seems that writes need to be 32-bit wide to start the xfer... + //*(volatile uint8_t*)QUADSPI->DR = *src++; + //--len; + QUADSPI->DR = *(uint32_t*)src; + src += 4; + len -= 4; + } + } + + // Wait for write to finish + while (!(QUADSPI->SR & QUADSPI_SR_TCF)) { + } + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag +} + +STATIC uint32_t qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) { + (void)self_in; + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag + + QUADSPI->DLR = len - 1; // number of bytes to read + + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 1 << QUADSPI_CCR_FMODE_Pos // indirect read mode + | 1 << QUADSPI_CCR_DMODE_Pos // data on 1 line + | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles + | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte + | 0 << QUADSPI_CCR_ADMODE_Pos // no address + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | cmd << QUADSPI_CCR_INSTRUCTION_Pos // read opcode + ; + + // Wait for read to finish + while (!(QUADSPI->SR & QUADSPI_SR_TCF)) { + } + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag + + // Read result + return QUADSPI->DR; +} + +STATIC void qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) { + (void)self_in; + // This assumes that cmd=0xeb + qspi_memory_map(); + memcpy(dest, (void*)(0x90000000 + addr), len); +} + +const mp_qspi_proto_t qspi_proto = { + .ioctl = qspi_ioctl, + .write_cmd_data = qspi_write_cmd_data, + .write_cmd_addr_data = qspi_write_cmd_addr_data, + .read_cmd = qspi_read_cmd, + .read_cmd_qaddr_qdata = qspi_read_cmd_qaddr_qdata, +}; + +#endif // defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2) diff --git a/ports/stm32/qspi.h b/ports/stm32/qspi.h new file mode 100644 index 0000000000..c774b12582 --- /dev/null +++ b/ports/stm32/qspi.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_QSPI_H +#define MICROPY_INCLUDED_STM32_QSPI_H + +#include "drivers/bus/qspi.h" + +extern const mp_qspi_proto_t qspi_proto; + +void qspi_init(void); +void qspi_memory_map(void); + +#endif // MICROPY_INCLUDED_STM32_QSPI_H From 512f4a6ad1c495760b50eca1bdee60314814b077 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 3 Mar 2018 23:58:03 +1100 Subject: [PATCH 395/828] tests/unix: Add coverage test for uio.resource_stream from frozen str. --- tests/unix/extra_coverage.py | 5 +++++ tests/unix/extra_coverage.py.exp | 1 + 2 files changed, 6 insertions(+) diff --git a/tests/unix/extra_coverage.py b/tests/unix/extra_coverage.py index 7a496aa879..65011198dd 100644 --- a/tests/unix/extra_coverage.py +++ b/tests/unix/extra_coverage.py @@ -71,3 +71,8 @@ try: import frzmpy2 except ZeroDivisionError: print('ZeroDivisionError') + +# test loading a resource from a frozen string +import uio +buf = uio.resource_stream('frzstr_pkg2', 'mod.py') +print(buf.read(21)) diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index d2e557fdcb..009874509d 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -104,3 +104,4 @@ frzstr_pkg2.mod frzmpy_pkg2.mod 1 ZeroDivisionError +b'# test frozen package' From e3d11b6a6e101b55aae5907539a3a8d9fd432721 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 4 Mar 2018 00:17:33 +1100 Subject: [PATCH 396/828] tests/extmod/time_ms_us: Add test for calling ticks_cpu(). This is just to test that the function exists and returns some kind of valid value. Although this file is for testing ms/us functions, put the ticks_cpu() test here so not to add a new test file. --- tests/extmod/time_ms_us.py | 3 +++ tests/extmod/time_ms_us.py.exp | 1 + 2 files changed, 4 insertions(+) diff --git a/tests/extmod/time_ms_us.py b/tests/extmod/time_ms_us.py index 31f07d31ba..4d0287da31 100644 --- a/tests/extmod/time_ms_us.py +++ b/tests/extmod/time_ms_us.py @@ -9,3 +9,6 @@ utime.sleep_ms(1) utime.sleep_us(1) print(utime.ticks_diff(utime.ticks_ms(), utime.ticks_ms()) <= 1) print(utime.ticks_diff(utime.ticks_us(), utime.ticks_us()) <= 500) + +# ticks_cpu may not be implemented, at least make sure it doesn't decrease +print(utime.ticks_diff(utime.ticks_cpu(), utime.ticks_cpu()) >= 0) diff --git a/tests/extmod/time_ms_us.py.exp b/tests/extmod/time_ms_us.py.exp index dbde422651..b8ca7e7ef0 100644 --- a/tests/extmod/time_ms_us.py.exp +++ b/tests/extmod/time_ms_us.py.exp @@ -1,2 +1,3 @@ True True +True From 0acf868bb72e0b94683f447baa367999d401b770 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 4 Mar 2018 00:38:15 +1100 Subject: [PATCH 397/828] tests/extmod/time_ms_us: Fix ticks tests, ticks_diff args are reversed. --- tests/extmod/time_ms_us.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/extmod/time_ms_us.py b/tests/extmod/time_ms_us.py index 4d0287da31..135cf1e096 100644 --- a/tests/extmod/time_ms_us.py +++ b/tests/extmod/time_ms_us.py @@ -7,8 +7,16 @@ except AttributeError: utime.sleep_ms(1) utime.sleep_us(1) -print(utime.ticks_diff(utime.ticks_ms(), utime.ticks_ms()) <= 1) -print(utime.ticks_diff(utime.ticks_us(), utime.ticks_us()) <= 500) + +t0 = utime.ticks_ms() +t1 = utime.ticks_ms() +print(0 <= utime.ticks_diff(t1, t0) <= 1) + +t0 = utime.ticks_us() +t1 = utime.ticks_us() +print(0 <= utime.ticks_diff(t1, t0) <= 500) # ticks_cpu may not be implemented, at least make sure it doesn't decrease -print(utime.ticks_diff(utime.ticks_cpu(), utime.ticks_cpu()) >= 0) +t0 = utime.ticks_cpu() +t1 = utime.ticks_cpu() +print(utime.ticks_diff(t1, t0) >= 0) From b691aa0aaeb9f55f96d9ed39f214f0a9e555c94d Mon Sep 17 00:00:00 2001 From: Olivier Ortigues Date: Fri, 23 Feb 2018 15:41:51 +0100 Subject: [PATCH 398/828] esp8266/esppwm: Always start timer to avoid glitch from full to nonfull. The PWM at full value was not considered as an "active" channel so if no other channel was used the timer used to mange PWM was not started. So when another duty value was set the PWM timer restarted and there was a visible glitch when driving LEDs. Such a glitch can be seen with the following code (assuming active-low LED on pin 0): p = machine.PWM(machine.Pin(0)) p.duty(1023) # full width, LED is off p.duty(1022) # LED flashes brightly then goes dim This patch fixes the glitch. --- ports/esp8266/esppwm.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/ports/esp8266/esppwm.c b/ports/esp8266/esppwm.c index f56eafc1b6..33eaf3b9a1 100644 --- a/ports/esp8266/esppwm.c +++ b/ports/esp8266/esppwm.c @@ -190,11 +190,8 @@ pwm_start(void) // start gpio_output_set(local_single[0].gpio_set, local_single[0].gpio_clear, pwm_gpio, 0); - // yeah, if all channels' duty is 0 or 255, don't need to start timer, otherwise start... - if (*local_channel != 1) { - pwm_timer_down = 0; - RTC_REG_WRITE(FRC1_LOAD_ADDRESS, local_single[0].h_time); - } + pwm_timer_down = 0; + RTC_REG_WRITE(FRC1_LOAD_ADDRESS, local_single[0].h_time); } if (pwm_toggle == 1) { @@ -319,11 +316,7 @@ pwm_tim1_intr_handler(void *dummy) pwm_current_channel = 0; - if (*pwm_channel != 1) { - RTC_REG_WRITE(FRC1_LOAD_ADDRESS, pwm_single[pwm_current_channel].h_time); - } else { - pwm_timer_down = 1; - } + RTC_REG_WRITE(FRC1_LOAD_ADDRESS, pwm_single[pwm_current_channel].h_time); } else { gpio_output_set(pwm_single[pwm_current_channel].gpio_set, pwm_single[pwm_current_channel].gpio_clear, From d4470af239ffb536f3fbf610060ddb62789d3045 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 5 Mar 2018 14:06:45 +1100 Subject: [PATCH 399/828] esp32: Revert "esp32/machine_touchpad: Swap pins 32 and 33." This reverts commit 5a82ba8e073f847985595a46fb2f0c12f4389bbc. Touch sensor 8 and 9 have a mismatch in some of their registers and this is now fixed in software by the ESP IDF. --- ports/esp32/machine_touchpad.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/esp32/machine_touchpad.c b/ports/esp32/machine_touchpad.c index ff31ccf69a..96de1a2a1d 100644 --- a/ports/esp32/machine_touchpad.c +++ b/ports/esp32/machine_touchpad.c @@ -51,8 +51,8 @@ STATIC const mtp_obj_t touchpad_obj[] = { {{&machine_touchpad_type}, GPIO_NUM_12, TOUCH_PAD_NUM5}, {{&machine_touchpad_type}, GPIO_NUM_14, TOUCH_PAD_NUM6}, {{&machine_touchpad_type}, GPIO_NUM_27, TOUCH_PAD_NUM7}, - {{&machine_touchpad_type}, GPIO_NUM_32, TOUCH_PAD_NUM8}, - {{&machine_touchpad_type}, GPIO_NUM_33, TOUCH_PAD_NUM9}, + {{&machine_touchpad_type}, GPIO_NUM_33, TOUCH_PAD_NUM8}, + {{&machine_touchpad_type}, GPIO_NUM_32, TOUCH_PAD_NUM9}, }; STATIC mp_obj_t mtp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, From 478ce8f7e3136214f7050965b5ce64bcdabe0bd3 Mon Sep 17 00:00:00 2001 From: Lee Seong Per Date: Thu, 22 Feb 2018 16:29:40 +0800 Subject: [PATCH 400/828] esp32/modnetwork: Implement status('stations') to list STAs in AP mode. The method returns a list of tuples representing the connected stations. The first element of the tuple is the MAC address of the station. --- ports/esp32/modnetwork.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index ef817de52d..ef5292be3c 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -275,11 +275,36 @@ STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_disconnect_obj, esp_disconnect); -STATIC mp_obj_t esp_status(mp_obj_t self_in) { +STATIC mp_obj_t esp_status(size_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + // no arguments: return None until link status is implemented + return mp_const_none; + } + + // one argument: return status based on query parameter + switch ((uintptr_t)args[1]) { + case (uintptr_t)MP_OBJ_NEW_QSTR(MP_QSTR_stations): { + // return list of connected stations, only if in soft-AP mode + require_if(args[0], WIFI_IF_AP); + wifi_sta_list_t station_list; + ESP_EXCEPTIONS(esp_wifi_ap_get_sta_list(&station_list)); + wifi_sta_info_t *stations = (wifi_sta_info_t*)station_list.sta; + mp_obj_t list = mp_obj_new_list(0, NULL); + for (int i = 0; i < station_list.num; ++i) { + mp_obj_tuple_t *t = mp_obj_new_tuple(1, NULL); + t->items[0] = mp_obj_new_bytes(stations[i].mac, sizeof(stations[i].mac)); + mp_obj_list_append(list, t); + } + return list; + } + + default: + mp_raise_ValueError("unknown status param"); + } + return mp_const_none; } - -STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_status_obj, esp_status); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_status_obj, 1, 2, esp_status); STATIC mp_obj_t esp_scan(mp_obj_t self_in) { // check that STA mode is active From 6e09320b4c5b3b6630acb70ee5c28154a757e61a Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 5 Mar 2018 19:07:39 +1100 Subject: [PATCH 401/828] docs/library/usocket: Make xref to uerrno explicitly a module reference. --- docs/library/usocket.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/library/usocket.rst b/docs/library/usocket.rst index de55fc14ca..3ae477a9ac 100644 --- a/docs/library/usocket.rst +++ b/docs/library/usocket.rst @@ -99,7 +99,7 @@ Functions of error in this function. MicroPython doesn't have ``socket.gaierror`` and raises OSError directly. Note that error numbers of `getaddrinfo()` form a separate namespace and may not match error numbers from - `uerrno` module. To distinguish `getaddrinfo()` errors, they are + the :mod:`uerrno` module. To distinguish `getaddrinfo()` errors, they are represented by negative numbers, whereas standard system errors are positive numbers (error numbers are accessible using ``e.args[0]`` property from an exception object). The use of negative values is a provisional From a5fb699d87ffa178736021c4763d323be54e87d4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 5 Mar 2018 19:10:45 +1100 Subject: [PATCH 402/828] docs/library/micropython: Describe optimisation levels for opt_level(). --- docs/library/micropython.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/library/micropython.rst b/docs/library/micropython.rst index d1f923e31f..a6ea738ed5 100644 --- a/docs/library/micropython.rst +++ b/docs/library/micropython.rst @@ -33,6 +33,18 @@ Functions compilation of scripts, and returns ``None``. Otherwise it returns the current optimisation level. + The optimisation level controls the following compilation features: + + - Assertions: at level 0 assertion statements are enabled and compiled into the + bytecode; at levels 1 and higher assertions are not compiled. + - Built-in ``__debug__`` variable: at level 0 this variable expands to ``True``; + at levels 1 and higher it expands to ``False``. + - Source-code line numbers: at levels 0, 1 and 2 source-code line number are + stored along with the bytecode so that exceptions can report the line number + they occurred at; at levels 3 and higher line numbers are not stored. + + The default optimisation level is usually level 0. + .. function:: alloc_emergency_exception_buf(size) Allocate *size* bytes of RAM for the emergency exception buffer (a good From 63b003d52350b4c8468d000f544ae9a634de1493 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 7 Mar 2018 14:49:25 +1100 Subject: [PATCH 403/828] docs/library/uos: Create sections for distinct parts and document uname. --- docs/library/uos.rst | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/docs/library/uos.rst b/docs/library/uos.rst index c7fa4b3081..85754c5a12 100644 --- a/docs/library/uos.rst +++ b/docs/library/uos.rst @@ -6,11 +6,32 @@ |see_cpython_module| :mod:`python:os`. -The ``uos`` module contains functions for filesystem access and ``urandom`` -function. +The ``uos`` module contains functions for filesystem access and mounting, +terminal redirection and duplication, and the ``uname`` and ``urandom`` +functions. -Functions ---------- +General functions +----------------- + +.. function:: uname() + + Return a tuple (possibly a named tuple) containing information about the + underlying machine and/or its operating system. The tuple has five fields + in the following order, each of them being a string: + + * ``sysname`` -- the name of the underlying system + * ``nodename`` -- the network name (can be the same as ``sysname``) + * ``release`` -- the version of the underlying system + * ``version`` -- the MicroPython version and build date + * ``machine`` -- an identifier for the underlying hardware (eg board, CPU) + +.. function:: urandom(n) + + Return a bytes object with *n* random bytes. Whenever possible, it is + generated by the hardware random number generator. + +Filesystem access +----------------- .. function:: chdir(path) @@ -84,10 +105,8 @@ Functions Sync all filesystems. -.. function:: urandom(n) - - Return a bytes object with n random bytes. Whenever possible, it is - generated by the hardware random number generator. +Terminal redirection and duplication +------------------------------------ .. function:: dupterm(stream_object, index=0) From 8359210e71ee0c46434ef8b1056627597f0bf0bf Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 7 Mar 2018 14:50:38 +1100 Subject: [PATCH 404/828] docs/library/uos: Document mount, umount, VfsFat and block devices. --- docs/library/uos.rst | 116 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/docs/library/uos.rst b/docs/library/uos.rst index 85754c5a12..85adb6a4dd 100644 --- a/docs/library/uos.rst +++ b/docs/library/uos.rst @@ -127,3 +127,119 @@ Terminal redirection and duplication the slot given by *index*. The function returns the previous stream-like object in the given slot. + +Filesystem mounting +------------------- + +Some ports provide a Virtual Filesystem (VFS) and the ability to mount multiple +"real" filesystems within this VFS. Filesystem objects can be mounted at either +the root of the VFS, or at a subdirectory that lives in the root. This allows +dynamic and flexible configuration of the filesystem that is seen by Python +programs. Ports that have this functionality provide the :func:`mount` and +:func:`umount` functions, and possibly various filesystem implementations +represented by VFS classes. + +.. function:: mount(fsobj, mount_point, \*, readonly) + + Mount the filesystem object *fsobj* at the location in the VFS given by the + *mount_point* string. *fsobj* can be a a VFS object that has a ``mount()`` + method, or a block device. If it's a block device then the filesystem type + is automatically detected (an exception is raised if no filesystem was + recognised). *mount_point* may be ``'/'`` to mount *fsobj* at the root, + or ``'/'`` to mount it at a subdirectory under the root. + + If *readonly* is ``True`` then the filesystem is mounted read-only. + + During the mount process the method ``mount()`` is called on the filesystem + object. + + Will raise ``OSError(EPERM)`` if *mount_point* is already mounted. + +.. function:: umount(mount_point) + + Unmount a filesystem. *mount_point* can be a string naming the mount location, + or a previously-mounted filesystem object. During the unmount process the + method ``umount()`` is called on the filesystem object. + + Will raise ``OSError(EINVAL)`` if *mount_point* is not found. + +.. class:: VfsFat(block_dev) + + Create a filesystem object that uses the FAT filesystem format. Storage of + the FAT filesystem is provided by *block_dev*. + Objects created by this constructor can be mounted using :func:`mount`. + + .. staticmethod:: mkfs(block_dev) + + Build a FAT filesystem on *block_dev*. + +Block devices +------------- + +A block device is an object which implements the block protocol, which is a set +of methods described below by the :class:`AbstractBlockDev` class. A concrete +implementation of this class will usually allow access to the memory-like +functionality a piece of hardware (like flash memory). A block device can be +used by a particular filesystem driver to store the data for its filesystem. + +.. class:: AbstractBlockDev(...) + + Construct a block device object. The parameters to the constructor are + dependent on the specific block device. + + .. method:: readblocks(block_num, buf) + + Starting at *block_num*, read blocks from the device into *buf* (an array + of bytes). The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + + .. method:: writeblocks(block_num, buf) + + Starting at *block_num*, write blocks from *buf* (an array of bytes) to + the device. The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + + .. method:: ioctl(op, arg) + + Control the block device and query its parameters. The operation to + perform is given by *op* which is one of the following integers: + + - 1 -- initialise the device (*arg* is unused) + - 2 -- shutdown the device (*arg* is unused) + - 3 -- sync the device (*arg* is unused) + - 4 -- get a count of the number of blocks, should return an integer + (*arg* is unused) + - 5 -- get the number of bytes in a block, should return an integer, + or ``None`` in which case the default value of 512 is used + (*arg* is unused) + +By way of example, the following class will implement a block device that stores +its data in RAM using a ``bytearray``:: + + class RAMBlockDev: + def __init__(self, block_size, num_blocks): + self.block_size = block_size + self.data = bytearray(block_size * num_blocks) + + def readblocks(self, block_num, buf): + for i in range(len(buf)): + buf[i] = self.data[block_num * self.block_size + i] + + def writeblocks(self, block_num, buf): + for i in range(len(buf)): + self.data[block_num * self.block_size + i] = buf[i] + + def ioctl(self, op, arg): + if op == 4: # get number of blocks + return len(self.data) // self.block_size + if op == 5: # get block size + return self.block_size + +It can be used as follows:: + + import uos + + bdev = RAMBlockDev(512, 50) + uos.VfsFat.mkfs(bdev) + vfs = uos.VfsFat(bdev) + uos.mount(vfs, '/ramdisk') From 024edafea06ef92ebd2c2be7131e2a12f9dfc54b Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 7 Mar 2018 14:59:03 +1100 Subject: [PATCH 405/828] stm32/i2c: On F4 MCUs report the actual I2C SCL frequency. --- ports/stm32/i2c.c | 18 +++++++++++++----- ports/stm32/i2c.h | 2 +- ports/stm32/machine_i2c.c | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index 56c63684f5..b9ab16e123 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -191,9 +191,9 @@ STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) { "Unsupported I2C baudrate: %lu", baudrate)); } -uint32_t i2c_get_baudrate(I2C_InitTypeDef *init) { +uint32_t i2c_get_baudrate(I2C_HandleTypeDef *i2c) { for (int i = 0; i < NUM_BAUDRATE_TIMINGS; i++) { - if (pyb_i2c_baudrate_timing[i].timing == init->Timing) { + if (pyb_i2c_baudrate_timing[i].timing == i2c->Init.Timing) { return pyb_i2c_baudrate_timing[i].baudrate; } } @@ -210,8 +210,16 @@ STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) { init->DutyCycle = I2C_DUTYCYCLE_16_9; } -uint32_t i2c_get_baudrate(I2C_InitTypeDef *init) { - return init->ClockSpeed; +uint32_t i2c_get_baudrate(I2C_HandleTypeDef *i2c) { + uint32_t pfreq = i2c->Instance->CR2 & 0x3f; + uint32_t ccr = i2c->Instance->CCR & 0xfff; + if (i2c->Instance->CCR & 0x8000) { + // Fast mode, assume duty cycle of 16/9 + return pfreq * 40000 / ccr; + } else { + // Standard mode + return pfreq * 500000 / ccr; + } } #endif @@ -545,7 +553,7 @@ STATIC void pyb_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki mp_printf(print, "I2C(%u)", i2c_num); } else { if (in_master_mode(self)) { - mp_printf(print, "I2C(%u, I2C.MASTER, baudrate=%u)", i2c_num, i2c_get_baudrate(&self->i2c->Init)); + mp_printf(print, "I2C(%u, I2C.MASTER, baudrate=%u)", i2c_num, i2c_get_baudrate(self->i2c)); } else { mp_printf(print, "I2C(%u, I2C.SLAVE, addr=0x%02x)", i2c_num, (self->i2c->Instance->OAR1 >> 1) & 0x7f); } diff --git a/ports/stm32/i2c.h b/ports/stm32/i2c.h index f416c791ee..e17621f7c3 100644 --- a/ports/stm32/i2c.h +++ b/ports/stm32/i2c.h @@ -48,7 +48,7 @@ extern const pyb_i2c_obj_t pyb_i2c_obj[4]; void i2c_init0(void); void i2c_init(I2C_HandleTypeDef *i2c); void i2c_init_freq(const pyb_i2c_obj_t *self, mp_int_t freq); -uint32_t i2c_get_baudrate(I2C_InitTypeDef *init); +uint32_t i2c_get_baudrate(I2C_HandleTypeDef *i2c); void i2c_ev_irq_handler(mp_uint_t i2c_id); void i2c_er_irq_handler(mp_uint_t i2c_id); diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c index 1018a9b1a5..5822b8e672 100644 --- a/ports/stm32/machine_i2c.c +++ b/ports/stm32/machine_i2c.c @@ -88,7 +88,7 @@ STATIC void machine_hard_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "I2C(%u, freq=%u, timeout=%u)", self - &machine_hard_i2c_obj[0] + 1, - i2c_get_baudrate(&self->pyb->i2c->Init), + i2c_get_baudrate(self->pyb->i2c), *self->timeout); } From bda36206160150a244fd2c9e4b531d91e2d77aaf Mon Sep 17 00:00:00 2001 From: sec2 Date: Mon, 5 Mar 2018 16:36:32 +0800 Subject: [PATCH 406/828] stm32/boards/stm32f767_af.csv: Add ADC column to pin capability list. --- ports/stm32/boards/stm32f767_af.csv | 340 ++++++++++++++-------------- 1 file changed, 170 insertions(+), 170 deletions(-) diff --git a/ports/stm32/boards/stm32f767_af.csv b/ports/stm32/boards/stm32f767_af.csv index ab2e248bbf..0c8069ec26 100644 --- a/ports/stm32/boards/stm32f767_af.csv +++ b/ports/stm32/boards/stm32f767_af.csv @@ -1,170 +1,170 @@ -Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15 -,,SYS,I2C4/UART5/TIM1/2,TIM3/4/5,TIM8/9/10/11/LPTIM1/DFSDM1/CEC,I2C1/2/3/4/USART1/CEC,SPI1/I2S1/SPI2/I2S2/SPI3/I2S3/SPI4/5/6,SPI2/I2S2/SPI3/I2S3/SAI1/I2C4/UART4/DFSDM1,SPI2/I2S2/SPI3/I2S3/SPI6/USART1/2/3/UART5/DFSDM1/SPDIF,SPI6/SAI2/USART6/UART4/5/7/8/OTG_FS/SPDIF,CAN1/2/TIM12/13/14/QUADSPI/FMC/LCD,SAI2/QUADSPI/SDMMC2/DFSDM1/OTG2_HS/OTG1_FS/LCD,I2C4/CAN3/SDMMC2/ETH,UART7/FMC/SDMMC1/MDIOS/OTG2_FS,DCMI/LCD/DSI,LCD,SYS -PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,SAI2_SD_B,ETH_MII_CRS,,,,EVENTOUT -PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,LCD_R2,EVENTOUT -PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,MDIOS_MDIO,,LCD_R1,EVENTOUT -PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,LCD_B2,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT -PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,SPI6_NSS,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT -PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,SPI6_SCK,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT -PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,SPI6_MISO,TIM13_CH1,,,MDIOS_MDC,DCMI_PIXCLK,LCD_G2,EVENTOUT -PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SD,,,SPI6_MOSI,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT -PortA,PA8,MCO1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,CAN3_RX,UART7_RX,LCD_B3,LCD_R6,EVENTOUT -PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,,,,DCMI_D0,LCD_R5,EVENTOUT -PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,LCD_B4,OTG_FS_ID,,MDIOS_MDIO,DCMI_D1,LCD_B1,EVENTOUT -PortA,PA11,,TIM1_CH4,,,,SPI2_NSS/I2S2_WS,UART4_RX,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT -PortA,PA12,,TIM1_ETR,,,,SPI2_SCK/I2S2_CK,UART4_TX,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT -PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT -PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT -PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,HDMI_CEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,SPI6_NSS,UART4_RTS,,,CAN3_TX,UART7_TX,,,EVENTOUT -PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,DFSDM1_CKOUT,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,LCD_G1,EVENTOUT -PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM1_DATAIN1,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,LCD_G0,EVENTOUT -PortB,PB2,,,,,,,SAI1_SD_A,SPI3_MOSI/I2S3_SD,,QUADSPI_CLK,DFSDM1_CKIN1,,,,,EVENTOUT -PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,SPI6_SCK,,SDMMC2_D2,CAN3_RX,UART7_RX,,,EVENTOUT -PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,SPI2_NSS/I2S2_WS,SPI6_MISO,,SDMMC2_D3,CAN3_TX,UART7_TX,,,EVENTOUT -PortB,PB5,,UART5_RX,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,SPI6_MOSI,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,LCD_G7,EVENTOUT -PortB,PB6,,UART5_TX,TIM4_CH1,HDMI_CEC,I2C1_SCL,,DFSDM1_DATAIN5,USART1_TX,,CAN2_TX,QUADSPI_BK1_NCS,I2C4_SCL,FMC_SDNE1,DCMI_D5,,EVENTOUT -PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,DFSDM1_CKIN5,USART1_RX,,,,I2C4_SDA,FMC_NL,DCMI_VSYNC,,EVENTOUT -PortB,PB8,,I2C4_SCL,TIM4_CH3,TIM10_CH1,I2C1_SCL,,DFSDM1_CKIN7,UART5_RX,,CAN1_RX,SDMMC2_D4,ETH_MII_TXD3,SDMMC1_D4,DCMI_D6,LCD_B6,EVENTOUT -PortB,PB9,,I2C4_SDA,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,DFSDM1_DATAIN7,UART5_TX,,CAN1_TX,SDMMC2_D5,I2C4_SMBA,SDMMC1_D5,DCMI_D7,LCD_B7,EVENTOUT -PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,DFSDM1_DATAIN7,USART3_TX,,QUADSPI_BK1_NCS,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT -PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,DFSDM1_CKIN7,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DSI_TE,LCD_G5,EVENTOUT -PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,DFSDM1_DATAIN1,USART3_CK,UART5_RX,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,,,EVENTOUT -PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,DFSDM1_CKIN1,USART3_CTS,UART5_TX,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,,EVENTOUT -PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,USART1_TX,SPI2_MISO,DFSDM1_DATAIN2,USART3_RTS,UART4_RTS,TIM12_CH1,SDMMC2_D0,,OTG_HS_DM,,,EVENTOUT -PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,USART1_RX,SPI2_MOSI/I2S2_SD,DFSDM1_CKIN2,,UART4_CTS,TIM12_CH2,SDMMC2_D1,,OTG_HS_DP,,,EVENTOUT -PortC,PC0,,,,DFSDM1_CKIN0,,,DFSDM1_DATAIN4,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT -PortC,PC1,TRACED0,,,DFSDM1_DATAIN0,,SPI2_MOSI/I2S2_SD,SAI1_SD_A,,,,DFSDM1_CKIN4,ETH_MDC,MDIOS_MDC,,,EVENTOUT -PortC,PC2,,,,DFSDM1_CKIN1,,SPI2_MISO,DFSDM1_CKOUT,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT -PortC,PC3,,,,DFSDM1_DATAIN1,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT -PortC,PC4,,,,DFSDM1_CKIN2,,I2S1_MCK,,,SPDIFRX_IN2,,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT -PortC,PC5,,,,DFSDM1_DATAIN2,,,,,SPDIFRX_IN3,,,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,,,EVENTOUT -PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,DFSDM1_CKIN3,USART6_TX,FMC_NWAIT,SDMMC2_D6,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT -PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,DFSDM1_DATAIN3,USART6_RX,FMC_NE1,SDMMC2_D7,,SDMMC1_D7,DCMI_D1,LCD_G6,EVENTOUT -PortC,PC8,TRACED1,,TIM3_CH3,TIM8_CH3,,,,UART5_RTS,USART6_CK,FMC_NE2/FMC_NCE,,,SDMMC1_D0,DCMI_D2,,EVENTOUT -PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,UART5_CTS,,QUADSPI_BK1_IO0,LCD_G3,,SDMMC1_D1,DCMI_D3,LCD_B2,EVENTOUT -PortC,PC10,,,,DFSDM1_CKIN5,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,DCMI_D8,LCD_R2,EVENTOUT -PortC,PC11,,,,DFSDM1_DATAIN5,,,SPI3_MISO,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,DCMI_D4,,EVENTOUT -PortC,PC12,TRACED3,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDMMC1_CK,DCMI_D9,,EVENTOUT -PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT -PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT -PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT -PortD,PD0,,,,DFSDM1_CKIN6,,,DFSDM1_DATAIN7,,UART4_RX,CAN1_RX,,,FMC_D2,,,EVENTOUT -PortD,PD1,,,,DFSDM1_DATAIN6,,,DFSDM1_CKIN7,,UART4_TX,CAN1_TX,,,FMC_D3,,,EVENTOUT -PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,DCMI_D11,,EVENTOUT -PortD,PD3,,,,DFSDM1_CKOUT,,SPI2_SCK/I2S2_CK,DFSDM1_DATAIN0,USART2_CTS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT -PortD,PD4,,,,,,,DFSDM1_CKIN0,USART2_RTS,,,,,FMC_NOE,,,EVENTOUT -PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT -PortD,PD6,,,,DFSDM1_CKIN4,,SPI3_MOSI/I2S3_SD,SAI1_SD_A,USART2_RX,,,DFSDM1_DATAIN1,SDMMC2_CK,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT -PortD,PD7,,,,DFSDM1_DATAIN4,,SPI1_MOSI/I2S1_SD,DFSDM1_CKIN1,USART2_CK,SPDIFRX_IN0,,,SDMMC2_CMD,FMC_NE1,,,EVENTOUT -PortD,PD8,,,,DFSDM1_CKIN3,,,,USART3_TX,SPDIFRX_IN1,,,,FMC_D13,,,EVENTOUT -PortD,PD9,,,,DFSDM1_DATAIN3,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT -PortD,PD10,,,,DFSDM1_CKOUT,,,,USART3_CK,,,,,FMC_D15,,LCD_B3,EVENTOUT -PortD,PD11,,,,,I2C4_SMBA,,,USART3_CTS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16/FMC_CLE,,,EVENTOUT -PortD,PD12,,,TIM4_CH1,LPTIM1_IN1,I2C4_SCL,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17/FMC_ALE,,,EVENTOUT -PortD,PD13,,,TIM4_CH2,LPTIM1_OUT,I2C4_SDA,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT -PortD,PD14,,,TIM4_CH3,,,,,,UART8_CTS,,,,FMC_D0,,,EVENTOUT -PortD,PD15,,,TIM4_CH4,,,,,,UART8_RTS,,,,FMC_D1,,,EVENTOUT -PortE,PE0,,,TIM4_ETR,LPTIM1_ETR,,,,,UART8_RX,,SAI2_MCK_A,,FMC_NBL0,DCMI_D2,,EVENTOUT -PortE,PE1,,,,LPTIM1_IN2,,,,,UART8_TX,,,,FMC_NBL1,DCMI_D3,,EVENTOUT -PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,QUADSPI_BK1_IO2,,ETH_MII_TXD3,FMC_A23,,,EVENTOUT -PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT -PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,DFSDM1_DATAIN3,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT -PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,DFSDM1_CKIN3,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT -PortE,PE6,TRACED3,TIM1_BKIN2,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,SAI2_MCK_B,,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT -PortE,PE7,,TIM1_ETR,,,,,DFSDM1_DATAIN2,,UART7_RX,,QUADSPI_BK2_IO0,,FMC_D4,,,EVENTOUT -PortE,PE8,,TIM1_CH1N,,,,,DFSDM1_CKIN2,,UART7_TX,,QUADSPI_BK2_IO1,,FMC_D5,,,EVENTOUT -PortE,PE9,,TIM1_CH1,,,,,DFSDM1_CKOUT,,UART7_RTS,,QUADSPI_BK2_IO2,,FMC_D6,,,EVENTOUT -PortE,PE10,,TIM1_CH2N,,,,,DFSDM1_DATAIN4,,UART7_CTS,,QUADSPI_BK2_IO3,,FMC_D7,,,EVENTOUT -PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,DFSDM1_CKIN4,,,,SAI2_SD_B,,FMC_D8,,LCD_G3,EVENTOUT -PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,DFSDM1_DATAIN5,,,,SAI2_SCK_B,,FMC_D9,,LCD_B4,EVENTOUT -PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,DFSDM1_CKIN5,,,,SAI2_FS_B,,FMC_D10,,LCD_DE,EVENTOUT -PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCK_B,,FMC_D11,,LCD_CLK,EVENTOUT -PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FMC_D12,,LCD_R7,EVENTOUT -PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT -PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT -PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT -PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT -PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT -PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT -PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_RX,QUADSPI_BK1_IO3,,,,,,EVENTOUT -PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_TX,QUADSPI_BK1_IO2,,,,,,EVENTOUT -PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,UART7_RTS,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT -PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,UART7_CTS,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT -PortF,PF10,,,,,,,,,,QUADSPI_CLK,,,,DCMI_D11,LCD_DE,EVENTOUT -PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,DCMI_D12,,EVENTOUT -PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT -PortF,PF13,,,,,I2C4_SMBA,,DFSDM1_DATAIN6,,,,,,FMC_A7,,,EVENTOUT -PortF,PF14,,,,,I2C4_SCL,,DFSDM1_CKIN6,,,,,,FMC_A8,,,EVENTOUT -PortF,PF15,,,,,I2C4_SDA,,,,,,,,FMC_A9,,,EVENTOUT -PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT -PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT -PortG,PG2,,,,,,,,,,,,,FMC_A12,,,EVENTOUT -PortG,PG3,,,,,,,,,,,,,FMC_A13,,,EVENTOUT -PortG,PG4,,,,,,,,,,,,,FMC_A14/FMC_BA0,,,EVENTOUT -PortG,PG5,,,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT -PortG,PG6,,,,,,,,,,,,,FMC_NE3,DCMI_D12,LCD_R7,EVENTOUT -PortG,PG7,,,,,,,SAI1_MCLK_A,,USART6_CK,,,,FMC_INT,DCMI_D13,LCD_CLK,EVENTOUT -PortG,PG8,,,,,,SPI6_NSS,,SPDIFRX_IN2,USART6_RTS,,,ETH_PPS_OUT,FMC_SDCLK,,LCD_G7,EVENTOUT -PortG,PG9,,,,,,SPI1_MISO,,SPDIFRX_IN3,USART6_RX,QUADSPI_BK2_IO2,SAI2_FS_B,SDMMC2_D0,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT -PortG,PG10,,,,,,SPI1_NSS/I2S1_WS,,,,LCD_G3,SAI2_SD_B,SDMMC2_D1,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT -PortG,PG11,,,,,,SPI1_SCK/I2S1_CK,,SPDIFRX_IN0,,,SDMMC2_D2,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DCMI_D3,LCD_B3,EVENTOUT -PortG,PG12,,,,LPTIM1_IN1,,SPI6_MISO,,SPDIFRX_IN1,USART6_RTS,LCD_B4,,SDMMC2_D3,FMC_NE4,,LCD_B1,EVENTOUT -PortG,PG13,TRACED0,,,LPTIM1_OUT,,SPI6_SCK,,,USART6_CTS,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,LCD_R0,EVENTOUT -PortG,PG14,TRACED1,,,LPTIM1_ETR,,SPI6_MOSI,,,USART6_TX,QUADSPI_BK2_IO3,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,LCD_B0,EVENTOUT -PortG,PG15,,,,,,,,,USART6_CTS,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT -PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT -PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT -PortH,PH2,,,,LPTIM1_IN2,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT -PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT -PortH,PH4,,,,,I2C2_SCL,,,,,LCD_G5,OTG_HS_ULPI_NXT,,,,LCD_G4,EVENTOUT -PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT -PortH,PH6,,,,,I2C2_SMBA,SPI5_SCK,,,,TIM12_CH1,,ETH_MII_RXD2,FMC_SDNE1,DCMI_D8,,EVENTOUT -PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,EVENTOUT -PortH,PH8,,,,,I2C3_SDA,,,,,,,,FMC_D16,DCMI_HSYNC,LCD_R2,EVENTOUT -PortH,PH9,,,,,I2C3_SMBA,,,,,TIM12_CH2,,,FMC_D17,DCMI_D0,LCD_R3,EVENTOUT -PortH,PH10,,,TIM5_CH1,,I2C4_SMBA,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT -PortH,PH11,,,TIM5_CH2,,I2C4_SCL,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT -PortH,PH12,,,TIM5_CH3,,I2C4_SDA,,,,,,,,FMC_D20,DCMI_D3,LCD_R6,EVENTOUT -PortH,PH13,,,,TIM8_CH1N,,,,,UART4_TX,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT -PortH,PH14,,,,TIM8_CH2N,,,,,UART4_RX,CAN1_RX,,,FMC_D22,DCMI_D4,LCD_G3,EVENTOUT -PortH,PH15,,,,TIM8_CH3N,,,,,,,,,FMC_D23,DCMI_D11,LCD_G4,EVENTOUT -PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,,,,FMC_D24,DCMI_D13,LCD_G5,EVENTOUT -PortI,PI1,,,,TIM8_BKIN2,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT -PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT -PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT -PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCK_A,,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT -PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT -PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT -PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,DCMI_D7,LCD_B7,EVENTOUT -PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT -PortI,PI9,,,,,,,,,UART4_RX,CAN1_RX,,,FMC_D30,,LCD_VSYNC,EVENTOUT -PortI,PI10,,,,,,,,,,,,ETH_MII_RX_ER,FMC_D31,,LCD_HSYNC,EVENTOUT -PortI,PI11,,,,,,,,,,LCD_G6,OTG_HS_ULPI_DIR,,,,,EVENTOUT -PortI,PI12,,,,,,,,,,,,,,,LCD_HSYNC,EVENTOUT -PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT -PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT -PortI,PI15,,,,,,,,,,LCD_G2,,,,,LCD_R0,EVENTOUT -PortJ,PJ0,,,,,,,,,,LCD_R7,,,,,LCD_R1,EVENTOUT -PortJ,PJ1,,,,,,,,,,,,,,,LCD_R2,EVENTOUT -PortJ,PJ2,,,,,,,,,,,,,,DSI_TE,LCD_R3,EVENTOUT -PortJ,PJ3,,,,,,,,,,,,,,,LCD_R4,EVENTOUT -PortJ,PJ4,,,,,,,,,,,,,,,LCD_R5,EVENTOUT -PortJ,PJ5,,,,,,,,,,,,,,,LCD_R6,EVENTOUT -PortJ,PJ6,,,,,,,,,,,,,,,LCD_R7,EVENTOUT -PortJ,PJ7,,,,,,,,,,,,,,,LCD_G0,EVENTOUT -PortJ,PJ8,,,,,,,,,,,,,,,LCD_G1,EVENTOUT -PortJ,PJ9,,,,,,,,,,,,,,,LCD_G2,EVENTOUT -PortJ,PJ10,,,,,,,,,,,,,,,LCD_G3,EVENTOUT -PortJ,PJ11,,,,,,,,,,,,,,,LCD_G4,EVENTOUT -PortJ,PJ12,,,,,,,,,,LCD_G3,,,,,LCD_B0,EVENTOUT -PortJ,PJ13,,,,,,,,,,LCD_G4,,,,,LCD_B1,EVENTOUT -PortJ,PJ14,,,,,,,,,,,,,,,LCD_B2,EVENTOUT -PortJ,PJ15,,,,,,,,,,,,,,,LCD_B3,EVENTOUT -PortK,PK0,,,,,,,,,,,,,,,LCD_G5,EVENTOUT -PortK,PK1,,,,,,,,,,,,,,,LCD_G6,EVENTOUT -PortK,PK2,,,,,,,,,,,,,,,LCD_G7,EVENTOUT -PortK,PK3,,,,,,,,,,,,,,,LCD_B4,EVENTOUT -PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT -PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT -PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT -PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, +,,SYS,I2C4/UART5/TIM1/2,TIM3/4/5,TIM8/9/10/11/LPTIM1/DFSDM1/CEC,I2C1/2/3/4/USART1/CEC,SPI1/I2S1/SPI2/I2S2/SPI3/I2S3/SPI4/5/6,SPI2/I2S2/SPI3/I2S3/SAI1/I2C4/UART4/DFSDM1,SPI2/I2S2/SPI3/I2S3/SPI6/USART1/2/3/UART5/DFSDM1/SPDIF,SPI6/SAI2/USART6/UART4/5/7/8/OTG_FS/SPDIF,CAN1/2/TIM12/13/14/QUADSPI/FMC/LCD,SAI2/QUADSPI/SDMMC2/DFSDM1/OTG2_HS/OTG1_FS/LCD,I2C4/CAN3/SDMMC2/ETH,UART7/FMC/SDMMC1/MDIOS/OTG2_FS,DCMI/LCD/DSI,LCD,SYS,ADC +PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,SAI2_SD_B,ETH_MII_CRS,,,,EVENTOUT,ADC123_IN0 +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,LCD_R2,EVENTOUT,ADC123_IN1 +PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,MDIOS_MDIO,,LCD_R1,EVENTOUT,ADC123_IN2 +PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,LCD_B2,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT,ADC123_IN3 +PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,SPI6_NSS,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT,ADC12_IN4 +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,SPI6_SCK,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT,ADC12_IN5 +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,SPI6_MISO,TIM13_CH1,,,MDIOS_MDC,DCMI_PIXCLK,LCD_G2,EVENTOUT,ADC12_IN6 +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SD,,,SPI6_MOSI,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT,ADC12_IN7 +PortA,PA8,MCO1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,CAN3_RX,UART7_RX,LCD_B3,LCD_R6,EVENTOUT, +PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,,,,DCMI_D0,LCD_R5,EVENTOUT, +PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,LCD_B4,OTG_FS_ID,,MDIOS_MDIO,DCMI_D1,LCD_B1,EVENTOUT, +PortA,PA11,,TIM1_CH4,,,,SPI2_NSS/I2S2_WS,UART4_RX,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT, +PortA,PA12,,TIM1_ETR,,,,SPI2_SCK/I2S2_CK,UART4_TX,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,HDMI_CEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,SPI6_NSS,UART4_RTS,,,CAN3_TX,UART7_TX,,,EVENTOUT, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,DFSDM1_CKOUT,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,LCD_G1,EVENTOUT,ADC12_IN8 +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM1_DATAIN1,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,LCD_G0,EVENTOUT,ADC12_IN9 +PortB,PB2,,,,,,,SAI1_SD_A,SPI3_MOSI/I2S3_SD,,QUADSPI_CLK,DFSDM1_CKIN1,,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,SPI6_SCK,,SDMMC2_D2,CAN3_RX,UART7_RX,,,EVENTOUT, +PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,SPI2_NSS/I2S2_WS,SPI6_MISO,,SDMMC2_D3,CAN3_TX,UART7_TX,,,EVENTOUT, +PortB,PB5,,UART5_RX,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,SPI6_MOSI,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,LCD_G7,EVENTOUT, +PortB,PB6,,UART5_TX,TIM4_CH1,HDMI_CEC,I2C1_SCL,,DFSDM1_DATAIN5,USART1_TX,,CAN2_TX,QUADSPI_BK1_NCS,I2C4_SCL,FMC_SDNE1,DCMI_D5,,EVENTOUT, +PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,DFSDM1_CKIN5,USART1_RX,,,,I2C4_SDA,FMC_NL,DCMI_VSYNC,,EVENTOUT, +PortB,PB8,,I2C4_SCL,TIM4_CH3,TIM10_CH1,I2C1_SCL,,DFSDM1_CKIN7,UART5_RX,,CAN1_RX,SDMMC2_D4,ETH_MII_TXD3,SDMMC1_D4,DCMI_D6,LCD_B6,EVENTOUT, +PortB,PB9,,I2C4_SDA,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,DFSDM1_DATAIN7,UART5_TX,,CAN1_TX,SDMMC2_D5,I2C4_SMBA,SDMMC1_D5,DCMI_D7,LCD_B7,EVENTOUT, +PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,DFSDM1_DATAIN7,USART3_TX,,QUADSPI_BK1_NCS,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT, +PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,DFSDM1_CKIN7,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DSI_TE,LCD_G5,EVENTOUT, +PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,DFSDM1_DATAIN1,USART3_CK,UART5_RX,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,,,EVENTOUT, +PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,DFSDM1_CKIN1,USART3_CTS,UART5_TX,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,,EVENTOUT, +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,USART1_TX,SPI2_MISO,DFSDM1_DATAIN2,USART3_RTS,UART4_RTS,TIM12_CH1,SDMMC2_D0,,OTG_HS_DM,,,EVENTOUT, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,USART1_RX,SPI2_MOSI/I2S2_SD,DFSDM1_CKIN2,,UART4_CTS,TIM12_CH2,SDMMC2_D1,,OTG_HS_DP,,,EVENTOUT, +PortC,PC0,,,,DFSDM1_CKIN0,,,DFSDM1_DATAIN4,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT,ADC123_IN10 +PortC,PC1,TRACED0,,,DFSDM1_DATAIN0,,SPI2_MOSI/I2S2_SD,SAI1_SD_A,,,,DFSDM1_CKIN4,ETH_MDC,MDIOS_MDC,,,EVENTOUT,ADC123_IN11 +PortC,PC2,,,,DFSDM1_CKIN1,,SPI2_MISO,DFSDM1_CKOUT,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT,ADC123_IN12 +PortC,PC3,,,,DFSDM1_DATAIN1,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT,ADC123_IN13 +PortC,PC4,,,,DFSDM1_CKIN2,,I2S1_MCK,,,SPDIFRX_IN2,,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT,ADC12_IN14 +PortC,PC5,,,,DFSDM1_DATAIN2,,,,,SPDIFRX_IN3,,,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,,,EVENTOUT,ADC12_IN15 +PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,DFSDM1_CKIN3,USART6_TX,FMC_NWAIT,SDMMC2_D6,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT, +PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,DFSDM1_DATAIN3,USART6_RX,FMC_NE1,SDMMC2_D7,,SDMMC1_D7,DCMI_D1,LCD_G6,EVENTOUT, +PortC,PC8,TRACED1,,TIM3_CH3,TIM8_CH3,,,,UART5_RTS,USART6_CK,FMC_NE2/FMC_NCE,,,SDMMC1_D0,DCMI_D2,,EVENTOUT, +PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,UART5_CTS,,QUADSPI_BK1_IO0,LCD_G3,,SDMMC1_D1,DCMI_D3,LCD_B2,EVENTOUT, +PortC,PC10,,,,DFSDM1_CKIN5,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,DCMI_D8,LCD_R2,EVENTOUT, +PortC,PC11,,,,DFSDM1_DATAIN5,,,SPI3_MISO,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,DCMI_D4,,EVENTOUT, +PortC,PC12,TRACED3,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDMMC1_CK,DCMI_D9,,EVENTOUT, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD0,,,,DFSDM1_CKIN6,,,DFSDM1_DATAIN7,,UART4_RX,CAN1_RX,,,FMC_D2,,,EVENTOUT, +PortD,PD1,,,,DFSDM1_DATAIN6,,,DFSDM1_CKIN7,,UART4_TX,CAN1_TX,,,FMC_D3,,,EVENTOUT, +PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,DCMI_D11,,EVENTOUT, +PortD,PD3,,,,DFSDM1_CKOUT,,SPI2_SCK/I2S2_CK,DFSDM1_DATAIN0,USART2_CTS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT, +PortD,PD4,,,,,,,DFSDM1_CKIN0,USART2_RTS,,,,,FMC_NOE,,,EVENTOUT, +PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT, +PortD,PD6,,,,DFSDM1_CKIN4,,SPI3_MOSI/I2S3_SD,SAI1_SD_A,USART2_RX,,,DFSDM1_DATAIN1,SDMMC2_CK,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT, +PortD,PD7,,,,DFSDM1_DATAIN4,,SPI1_MOSI/I2S1_SD,DFSDM1_CKIN1,USART2_CK,SPDIFRX_IN0,,,SDMMC2_CMD,FMC_NE1,,,EVENTOUT, +PortD,PD8,,,,DFSDM1_CKIN3,,,,USART3_TX,SPDIFRX_IN1,,,,FMC_D13,,,EVENTOUT, +PortD,PD9,,,,DFSDM1_DATAIN3,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT, +PortD,PD10,,,,DFSDM1_CKOUT,,,,USART3_CK,,,,,FMC_D15,,LCD_B3,EVENTOUT, +PortD,PD11,,,,,I2C4_SMBA,,,USART3_CTS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16/FMC_CLE,,,EVENTOUT, +PortD,PD12,,,TIM4_CH1,LPTIM1_IN1,I2C4_SCL,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17/FMC_ALE,,,EVENTOUT, +PortD,PD13,,,TIM4_CH2,LPTIM1_OUT,I2C4_SDA,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT, +PortD,PD14,,,TIM4_CH3,,,,,,UART8_CTS,,,,FMC_D0,,,EVENTOUT, +PortD,PD15,,,TIM4_CH4,,,,,,UART8_RTS,,,,FMC_D1,,,EVENTOUT, +PortE,PE0,,,TIM4_ETR,LPTIM1_ETR,,,,,UART8_RX,,SAI2_MCK_A,,FMC_NBL0,DCMI_D2,,EVENTOUT, +PortE,PE1,,,,LPTIM1_IN2,,,,,UART8_TX,,,,FMC_NBL1,DCMI_D3,,EVENTOUT, +PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,QUADSPI_BK1_IO2,,ETH_MII_TXD3,FMC_A23,,,EVENTOUT, +PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT, +PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,DFSDM1_DATAIN3,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT, +PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,DFSDM1_CKIN3,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT, +PortE,PE6,TRACED3,TIM1_BKIN2,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,SAI2_MCK_B,,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT, +PortE,PE7,,TIM1_ETR,,,,,DFSDM1_DATAIN2,,UART7_RX,,QUADSPI_BK2_IO0,,FMC_D4,,,EVENTOUT, +PortE,PE8,,TIM1_CH1N,,,,,DFSDM1_CKIN2,,UART7_TX,,QUADSPI_BK2_IO1,,FMC_D5,,,EVENTOUT, +PortE,PE9,,TIM1_CH1,,,,,DFSDM1_CKOUT,,UART7_RTS,,QUADSPI_BK2_IO2,,FMC_D6,,,EVENTOUT, +PortE,PE10,,TIM1_CH2N,,,,,DFSDM1_DATAIN4,,UART7_CTS,,QUADSPI_BK2_IO3,,FMC_D7,,,EVENTOUT, +PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,DFSDM1_CKIN4,,,,SAI2_SD_B,,FMC_D8,,LCD_G3,EVENTOUT, +PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,DFSDM1_DATAIN5,,,,SAI2_SCK_B,,FMC_D9,,LCD_B4,EVENTOUT, +PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,DFSDM1_CKIN5,,,,SAI2_FS_B,,FMC_D10,,LCD_DE,EVENTOUT, +PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCK_B,,FMC_D11,,LCD_CLK,EVENTOUT, +PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FMC_D12,,LCD_R7,EVENTOUT, +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT, +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT, +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT, +PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN9 +PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN14 +PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN15 +PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_RX,QUADSPI_BK1_IO3,,,,,,EVENTOUT,ADC3_IN4 +PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_TX,QUADSPI_BK1_IO2,,,,,,EVENTOUT,ADC3_IN5 +PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,UART7_RTS,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT,ADC3_IN6 +PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,UART7_CTS,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT,ADC3_IN7 +PortF,PF10,,,,,,,,,,QUADSPI_CLK,,,,DCMI_D11,LCD_DE,EVENTOUT,ADC3_IN8 +PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,DCMI_D12,,EVENTOUT, +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT, +PortF,PF13,,,,,I2C4_SMBA,,DFSDM1_DATAIN6,,,,,,FMC_A7,,,EVENTOUT, +PortF,PF14,,,,,I2C4_SCL,,DFSDM1_CKIN6,,,,,,FMC_A8,,,EVENTOUT, +PortF,PF15,,,,,I2C4_SDA,,,,,,,,FMC_A9,,,EVENTOUT, +PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT, +PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT, +PortG,PG2,,,,,,,,,,,,,FMC_A12,,,EVENTOUT, +PortG,PG3,,,,,,,,,,,,,FMC_A13,,,EVENTOUT, +PortG,PG4,,,,,,,,,,,,,FMC_A14/FMC_BA0,,,EVENTOUT, +PortG,PG5,,,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT, +PortG,PG6,,,,,,,,,,,,,FMC_NE3,DCMI_D12,LCD_R7,EVENTOUT, +PortG,PG7,,,,,,,SAI1_MCLK_A,,USART6_CK,,,,FMC_INT,DCMI_D13,LCD_CLK,EVENTOUT, +PortG,PG8,,,,,,SPI6_NSS,,SPDIFRX_IN2,USART6_RTS,,,ETH_PPS_OUT,FMC_SDCLK,,LCD_G7,EVENTOUT, +PortG,PG9,,,,,,SPI1_MISO,,SPDIFRX_IN3,USART6_RX,QUADSPI_BK2_IO2,SAI2_FS_B,SDMMC2_D0,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT, +PortG,PG10,,,,,,SPI1_NSS/I2S1_WS,,,,LCD_G3,SAI2_SD_B,SDMMC2_D1,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT, +PortG,PG11,,,,,,SPI1_SCK/I2S1_CK,,SPDIFRX_IN0,,,SDMMC2_D2,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DCMI_D3,LCD_B3,EVENTOUT, +PortG,PG12,,,,LPTIM1_IN1,,SPI6_MISO,,SPDIFRX_IN1,USART6_RTS,LCD_B4,,SDMMC2_D3,FMC_NE4,,LCD_B1,EVENTOUT, +PortG,PG13,TRACED0,,,LPTIM1_OUT,,SPI6_SCK,,,USART6_CTS,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,LCD_R0,EVENTOUT, +PortG,PG14,TRACED1,,,LPTIM1_ETR,,SPI6_MOSI,,,USART6_TX,QUADSPI_BK2_IO3,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,LCD_B0,EVENTOUT, +PortG,PG15,,,,,,,,,USART6_CTS,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH2,,,,LPTIM1_IN2,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT, +PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT, +PortH,PH4,,,,,I2C2_SCL,,,,,LCD_G5,OTG_HS_ULPI_NXT,,,,LCD_G4,EVENTOUT, +PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT, +PortH,PH6,,,,,I2C2_SMBA,SPI5_SCK,,,,TIM12_CH1,,ETH_MII_RXD2,FMC_SDNE1,DCMI_D8,,EVENTOUT, +PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,EVENTOUT, +PortH,PH8,,,,,I2C3_SDA,,,,,,,,FMC_D16,DCMI_HSYNC,LCD_R2,EVENTOUT, +PortH,PH9,,,,,I2C3_SMBA,,,,,TIM12_CH2,,,FMC_D17,DCMI_D0,LCD_R3,EVENTOUT, +PortH,PH10,,,TIM5_CH1,,I2C4_SMBA,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT, +PortH,PH11,,,TIM5_CH2,,I2C4_SCL,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT, +PortH,PH12,,,TIM5_CH3,,I2C4_SDA,,,,,,,,FMC_D20,DCMI_D3,LCD_R6,EVENTOUT, +PortH,PH13,,,,TIM8_CH1N,,,,,UART4_TX,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT, +PortH,PH14,,,,TIM8_CH2N,,,,,UART4_RX,CAN1_RX,,,FMC_D22,DCMI_D4,LCD_G3,EVENTOUT, +PortH,PH15,,,,TIM8_CH3N,,,,,,,,,FMC_D23,DCMI_D11,LCD_G4,EVENTOUT, +PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,,,,FMC_D24,DCMI_D13,LCD_G5,EVENTOUT, +PortI,PI1,,,,TIM8_BKIN2,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT, +PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT, +PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT, +PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCK_A,,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT, +PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT, +PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT, +PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,DCMI_D7,LCD_B7,EVENTOUT, +PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI9,,,,,,,,,UART4_RX,CAN1_RX,,,FMC_D30,,LCD_VSYNC,EVENTOUT, +PortI,PI10,,,,,,,,,,,,ETH_MII_RX_ER,FMC_D31,,LCD_HSYNC,EVENTOUT, +PortI,PI11,,,,,,,,,,LCD_G6,OTG_HS_ULPI_DIR,,,,,EVENTOUT, +PortI,PI12,,,,,,,,,,,,,,,LCD_HSYNC,EVENTOUT, +PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT, +PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT, +PortI,PI15,,,,,,,,,,LCD_G2,,,,,LCD_R0,EVENTOUT, +PortJ,PJ0,,,,,,,,,,LCD_R7,,,,,LCD_R1,EVENTOUT, +PortJ,PJ1,,,,,,,,,,,,,,,LCD_R2,EVENTOUT, +PortJ,PJ2,,,,,,,,,,,,,,DSI_TE,LCD_R3,EVENTOUT, +PortJ,PJ3,,,,,,,,,,,,,,,LCD_R4,EVENTOUT, +PortJ,PJ4,,,,,,,,,,,,,,,LCD_R5,EVENTOUT, +PortJ,PJ5,,,,,,,,,,,,,,,LCD_R6,EVENTOUT, +PortJ,PJ6,,,,,,,,,,,,,,,LCD_R7,EVENTOUT, +PortJ,PJ7,,,,,,,,,,,,,,,LCD_G0,EVENTOUT, +PortJ,PJ8,,,,,,,,,,,,,,,LCD_G1,EVENTOUT, +PortJ,PJ9,,,,,,,,,,,,,,,LCD_G2,EVENTOUT, +PortJ,PJ10,,,,,,,,,,,,,,,LCD_G3,EVENTOUT, +PortJ,PJ11,,,,,,,,,,,,,,,LCD_G4,EVENTOUT, +PortJ,PJ12,,,,,,,,,,LCD_G3,,,,,LCD_B0,EVENTOUT, +PortJ,PJ13,,,,,,,,,,LCD_G4,,,,,LCD_B1,EVENTOUT, +PortJ,PJ14,,,,,,,,,,,,,,,LCD_B2,EVENTOUT, +PortJ,PJ15,,,,,,,,,,,,,,,LCD_B3,EVENTOUT, +PortK,PK0,,,,,,,,,,,,,,,LCD_G5,EVENTOUT, +PortK,PK1,,,,,,,,,,,,,,,LCD_G6,EVENTOUT, +PortK,PK2,,,,,,,,,,,,,,,LCD_G7,EVENTOUT, +PortK,PK3,,,,,,,,,,,,,,,LCD_B4,EVENTOUT, +PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT, +PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT, +PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT, +PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT, From 250b24fe3668968e305f37ebb4dcd55d57ae65d1 Mon Sep 17 00:00:00 2001 From: sec2 Date: Mon, 5 Mar 2018 16:55:41 +0800 Subject: [PATCH 407/828] stm32/boards/NUCLEO_F767ZI: Update pins list to include 3 extra pins. --- ports/stm32/boards/NUCLEO_F767ZI/pins.csv | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/stm32/boards/NUCLEO_F767ZI/pins.csv b/ports/stm32/boards/NUCLEO_F767ZI/pins.csv index 897b1473e7..84506649ef 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/pins.csv +++ b/ports/stm32/boards/NUCLEO_F767ZI/pins.csv @@ -4,6 +4,9 @@ A2,PC3 A3,PF3 A4,PF5 A5,PF10 +A6,PB1 +A7,PC2 +A8,PF4 D0,PG9 D1,PG14 D2,PF15 From 0b88a9f02ebbe3142609fa134e118e47c8008175 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 8 Mar 2018 12:49:31 +1100 Subject: [PATCH 408/828] unix/coverage: Allow coverage tests to pass with debugging disabled. --- ports/unix/coverage.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 33533ad865..eba84f38b3 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -152,7 +152,11 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "%.2s %.3s\n", "abc", "abc"); // fixed string precision mp_printf(&mp_plat_print, "%.*s\n", -1, "abc"); // negative string precision mp_printf(&mp_plat_print, "%b %b\n", 0, 1); // bools + #ifndef NDEBUG mp_printf(&mp_plat_print, "%s\n", NULL); // null string + #else + mp_printf(&mp_plat_print, "(null)\n"); // without debugging mp_printf won't check for null + #endif mp_printf(&mp_plat_print, "%d\n", 0x80000000); // should print signed mp_printf(&mp_plat_print, "%u\n", 0x80000000); // should print unsigned mp_printf(&mp_plat_print, "%x\n", 0x80000000); // should print unsigned From 72adc381fba1652d41d9c187476177229aeb4ad0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 8 Mar 2018 12:50:07 +1100 Subject: [PATCH 409/828] tests/basics/builtin_enumerate: Add test for many pos args to enumerate. --- tests/basics/builtin_enumerate.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/basics/builtin_enumerate.py b/tests/basics/builtin_enumerate.py index 4f8239bf72..fcbf869767 100644 --- a/tests/basics/builtin_enumerate.py +++ b/tests/basics/builtin_enumerate.py @@ -14,3 +14,10 @@ print(list(enumerate(range(100)))) print(list(enumerate([1, 2, 3], start=1))) print(list(enumerate(iterable=[1, 2, 3]))) print(list(enumerate(iterable=[1, 2, 3], start=1))) + +# check handling of extra positional args (exercises some logic in mp_arg_parse_all) +# don't print anything because it doesn't error with MICROPY_CPYTHON_COMPAT disabled +try: + enumerate([], 1, 2) +except TypeError: + pass From a3c721772eea87744d49ee65b9dd157f28bbcb76 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 20 Feb 2018 15:58:36 +1100 Subject: [PATCH 410/828] stm32/boards: Add stm32h743_af.csv file describing H7 GPIO alt funcs. --- ports/stm32/boards/stm32h743_af.csv | 170 ++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 ports/stm32/boards/stm32h743_af.csv diff --git a/ports/stm32/boards/stm32h743_af.csv b/ports/stm32/boards/stm32h743_af.csv new file mode 100644 index 0000000000..24710d717b --- /dev/null +++ b/ports/stm32/boards/stm32h743_af.csv @@ -0,0 +1,170 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, +,,SYS,TIM1/2/16/17/LPTIM1/HRTIM1,SAI1/TIM3/4/5/12/HRTIM1,LPUART/TIM8/LPTIM2/3/4/5/HRTIM1/DFSDM,I2C1/2/3/4/USART1/TIM15/LPTIM2/DFSDM/CEC,SPI1/2/3/4/5/6/CEC,SPI2/3/SAI1/3/I2C4/UART4/DFSDM,SPI2/3/6/USART1/2/3/6/UART7/SDMMC1,SPI6/SAI2/4/UART4/5/8/LPUART/SDMMC1/SPDIFRX,SAI4/FDCAN1/2/TIM13/14/QUADSPI/FMC/SDMMC2/LCD/SPDIFRX,SAI2/4/TIM8/QUADSPI/SDMMC2/OTG1_HS/OTG2_FS/LCD,I2C4/UART7/SWPMI1/TIM1/8/DFSDM/SDMMC2/MDIOS/ETH,TIM1/8/FMC/SDMMC1/MDIOS/OTG1_FS/LCD,TIM1/DCMI/LCD/COMP,UART5/LCD,SYS,ADC +PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,TIM15_BKIN,,,USART2_CTS_NSS,UART4_TX,SDMMC2_CMD,SAI2_SD_B,ETH_MII_CRS,,,,EVENTOUT, +PortA,PA1,,TIM2_CH2,TIM5_CH2,LPTIM3_OUT,TIM15_CH1N,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,LCD_R2,EVENTOUT, +PortA,PA2,,TIM2_CH3,TIM5_CH3,LPTIM4_OUT,TIM15_CH1,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,MDIOS_MDIO,,LCD_R1,EVENTOUT, +PortA,PA3,,TIM2_CH4,TIM5_CH4,LPTIM5_OUT,TIM15_CH2,,,USART2_RX,,LCD_B2,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT, +PortA,PA4,,,TIM5_ETR,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,SPI6_NSS,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT, +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,SPI6_SCK,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT, +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO/I2S1_SDI,,,SPI6_MISO,TIM13_CH1,TIM8_BKIN_COMP12,MDIOS_MDC,TIM1_BKIN_COMP12,DCMI_PIXCLK,LCD_G2,EVENTOUT, +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SDO,,,SPI6_MOSI,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT, +PortA,PA8,MCO1,TIM1_CH1,HRTIM_CHB2,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,UART7_RX,TIM8_BKIN2_COMP12,LCD_B3,LCD_R6,EVENTOUT, +PortA,PA9,,TIM1_CH2,HRTIM_CHC1,LPUART1_TX,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,CAN1_RXFD,,ETH_TX_ER,,DCMI_D0,LCD_R5,EVENTOUT, +PortA,PA10,,TIM1_CH3,HRTIM_CHC2,LPUART1_RX,,,,USART1_RX,,CAN1_TXFD,OTG_FS_ID,MDIOS_MDIO,LCD_B4,DCMI_D1,LCD_B1,EVENTOUT, +PortA,PA11,,TIM1_CH4,HRTIM_CHD1,LPUART1_CTS,,SPI2_NSS/I2S2_WS,UART4_RX,USART1_CTS_NSS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT, +PortA,PA12,,TIM1_ETR,HRTIM_CHD2,LPUART1_RTS,,SPI2_SCK/I2S2_CK,UART4_TX,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,HRTIM_FLT1,,HDMI_CEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,SPI6_NSS,UART4_RTS,,,UART7_TX,,,,EVENTOUT, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,DFSDM_CKOUT,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,LCD_G1,EVENTOUT, +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM_DATIN1,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,LCD_G0,EVENTOUT, +PortB,PB2,,,SAI1_D1,,DFSDM_CKIN1,,SAI1_SD_A,SPI3_MOSI/I2S3_SDO,SAI4_SD_A,QUADSPI_CLK,SAI4_D1,ETH_TX_ER,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,HRTIM_FLT4,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,SPI6_SCK,SDMMC2_D2,,UART7_RX,,,,EVENTOUT, +PortB,PB4,NJTRST,TIM16_BKIN,TIM3_CH1,HRTIM_EEV6,,SPI1_MISO/I2S1_SDI,SPI3_MISO/I2S3_SDI,SPI2_NSS/I2S2_WS,SPI6_MISO,SDMMC2_D3,,UART7_TX,,,,EVENTOUT, +PortB,PB5,,TIM17_BKIN,TIM3_CH2,HRTIM_EEV7,I2C1_SMBA,SPI1_MOSI/I2S1_SDO,I2C4_SMBA,SPI3_MOSI/I2S3_SDO,SPI6_MOSI,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,UART5_RX,EVENTOUT, +PortB,PB6,,TIM16_CH1N,TIM4_CH1,HRTIM_EEV8,I2C1_SCL,HDMI_CEC,I2C4_SCL,USART1_TX,LPUART1_TX,CAN2_TX,QUADSPI_BK1_NCS,DFSDM_DATIN5,FMC_SDNE1,DCMI_D5,UART5_TX,EVENTOUT, +PortB,PB7,,TIM17_CH1N,TIM4_CH2,HRTIM_EEV9,I2C1_SDA,,I2C4_SDA,USART1_RX,LPUART1_RX,CAN2_TXFD,,DFSDM_CKIN5,FMC_NL,DCMI_VSYNC,,EVENTOUT, +PortB,PB8,,TIM16_CH1,TIM4_CH3,DFSDM_CKIN7,I2C1_SCL,,I2C4_SCL,SDMMC1_CKIN,UART4_RX,CAN1_RX,SDMMC2_D4,ETH_MII_TXD3,SDMMC1_D4,DCMI_D6,LCD_B6,EVENTOUT, +PortB,PB9,,TIM17_CH1,TIM4_CH4,DFSDM_DATIN7,I2C1_SDA,SPI2_NSS/I2S2_WS,I2C4_SDA,SDMMC1_CDIR,UART4_TX,CAN1_TX,SDMMC2_D5,I2C4_SMBA,SDMMC1_D5,DCMI_D7,LCD_B7,EVENTOUT, +PortB,PB10,,TIM2_CH3,HRTIM_SCOUT,LPTIM2_IN1,I2C2_SCL,SPI2_SCK/I2S2_CK,DFSDM_DATIN7,USART3_TX,,QUADSPI_BK1_NCS,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT, +PortB,PB11,,TIM2_CH4,HRTIM_SCIN,LPTIM2_ETR,I2C2_SDA,,DFSDM_CKIN7,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,,LCD_G5,EVENTOUT, +PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,DFSDM_DATIN1,USART3_CK,,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,TIM1_BKIN_COMP12,UART5_RX,EVENTOUT, +PortB,PB13,,TIM1_CH1N,,LPTIM2_OUT,,SPI2_SCK/I2S2_CK,DFSDM_CKIN1,USART3_CTS_NSS,,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,UART5_TX,EVENTOUT, +PortB,PB14,,TIM1_CH2N,TIM12_CH1,TIM8_CH2N,USART1_TX,SPI2_MISO/I2S2_SDI,DFSDM_DATIN2,USART3_RTS,UART4_RTS,SDMMC2_D0,,,OTG_HS_DM,,,EVENTOUT, +PortB,PB15,RTC_REFIN,TIM1_CH3N,TIM12_CH2,TIM8_CH3N,USART1_RX,SPI2_MOSI/I2S2_SDO,DFSDM_CKIN2,,UART4_CTS,SDMMC2_D1,,,OTG_HS_DP,,,EVENTOUT, +PortC,PC0,,,,DFSDM_CKIN0,,,DFSDM_DATIN4,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT, +PortC,PC1,TRACED0,,SAI1_D1,DFSDM_DATIN0,DFSDM_CKIN4,SPI2_MOSI/I2S2_SDO,SAI1_SD_A,,SAI4_SD_A,SDMMC2_CK,SAI4_D1,ETH_MDC,MDIOS_MDC,,,EVENTOUT, +PortC,PC2,,,,DFSDM_CKIN1,,SPI2_MISO/I2S2_SDI,DFSDM_CKOUT,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT, +PortC,PC3,,,,DFSDM_DATIN1,,SPI2_MOSI/I2S2_SDO,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT, +PortC,PC4,,,,DFSDM_CKIN2,,I2S1_MCK,,,,SPDIFRX_IN2,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT, +PortC,PC5,,,SAI1_D3,DFSDM_DATIN2,,,,,,SPDIFRX_IN3,SAI4_D3,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,COMP_1_OUT,,EVENTOUT, +PortC,PC6,,HRTIM_CHA1,TIM3_CH1,TIM8_CH1,DFSDM_CKIN3,I2S2_MCK,,USART6_TX,SDMMC1_D0DIR,FMC_NWAIT,SDMMC2_D6,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT, +PortC,PC7,TRGIO,HRTIM_CHA2,TIM3_CH2,TIM8_CH2,DFSDM_DATIN3,,I2S3_MCK,USART6_RX,SDMMC1_D123DIR,FMC_NE1,SDMMC2_D7,SWPMI_TX,SDMMC1_D7,DCMI_D1,LCD_G6,EVENTOUT, +PortC,PC8,TRACED1,HRTIM_CHB1,TIM3_CH3,TIM8_CH3,,,,USART6_CK,UART5_RTS,FMC_NE2/FMC_NCE,,SWPMI_RX,SDMMC1_D0,DCMI_D2,,EVENTOUT, +PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,,UART5_CTS,QUADSPI_BK1_IO0,LCD_G3,SWPMI_SUSPEND,SDMMC1_D1,DCMI_D3,LCD_B2,EVENTOUT, +PortC,PC10,,,HRTIM_EEV1,DFSDM_CKIN5,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,DCMI_D8,LCD_R2,EVENTOUT, +PortC,PC11,,,HRTIM_FLT2,DFSDM_DATIN5,,,SPI3_MISO/I2S3_SDI,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,DCMI_D4,,EVENTOUT, +PortC,PC12,TRACED3,,HRTIM_EEV2,,,,SPI3_MOSI/I2S3_SDO,USART3_CK,UART5_TX,,,,SDMMC1_CK,DCMI_D9,,EVENTOUT, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD0,,,,DFSDM_CKIN6,,,SAI3_SCK_A,,UART4_RX,CAN1_RX,,,FMC_D2/FMC_DA2,,,EVENTOUT, +PortD,PD1,,,,DFSDM_DATIN6,,,SAI3_SD_A,,UART4_TX,CAN1_TX,,,FMC_D3/FMC_DA3,,,EVENTOUT, +PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,DCMI_D11,,EVENTOUT, +PortD,PD3,,,,DFSDM_CKOUT,,SPI2_SCK/I2S2_CK,,USART2_CTS_NSS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT, +PortD,PD4,,,HRTIM_FLT3,,,,SAI3_FS_A,USART2_RTS,,CAN1_RXFD,,,FMC_NOE,,,EVENTOUT, +PortD,PD5,,,HRTIM_EEV3,,,,,USART2_TX,,CAN1_TXFD,,,FMC_NWE,,,EVENTOUT, +PortD,PD6,,,SAI1_D1,DFSDM_CKIN4,DFSDM_DATIN1,SPI3_MOSI/I2S3_SDO,SAI1_SD_A,USART2_RX,SAI4_SD_A,CAN2_RXFD,SAI4_D1,SDMMC2_CK,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT, +PortD,PD7,,,,DFSDM_DATIN4,,SPI1_MOSI/I2S1_SDO,DFSDM_CKIN1,USART2_CK,,SPDIFRX_IN0,,SDMMC2_CMD,FMC_NE1,,,EVENTOUT, +PortD,PD8,,,,DFSDM_CKIN3,,,SAI3_SCK_B,USART3_TX,,SPDIFRX_IN1,,,FMC_D13/FMC_DA13,,,EVENTOUT, +PortD,PD9,,,,DFSDM_DATIN3,,,SAI3_SD_B,USART3_RX,,CAN2_RXFD,,,FMC_D14/FMC_DA14,,,EVENTOUT, +PortD,PD10,,,,DFSDM_CKOUT,,,SAI3_FS_B,USART3_CK,,CAN2_TXFD,,,FMC_D15/FMC_DA15,,LCD_B3,EVENTOUT, +PortD,PD11,,,,LPTIM2_IN2,I2C4_SMBA,,,USART3_CTS_NSS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16,,,EVENTOUT, +PortD,PD12,,LPTIM1_IN1,TIM4_CH1,LPTIM2_IN1,I2C4_SCL,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17,,,EVENTOUT, +PortD,PD13,,LPTIM1_OUT,TIM4_CH2,,I2C4_SDA,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT, +PortD,PD14,,,TIM4_CH3,,,,SAI3_MCLK_B,,UART8_CTS,,,,FMC_D0/FMC_DA0,,,EVENTOUT, +PortD,PD15,,,TIM4_CH4,,,,SAI3_MCLK_A,,UART8_RTS,,,,FMC_D1/FMC_DA1,,,EVENTOUT, +PortE,PE0,,LPTIM1_ETR,TIM4_ETR,HRTIM_SCIN,LPTIM2_ETR,,,,UART8_RX,CAN1_RXFD,SAI2_MCK_A,,FMC_NBL0,DCMI_D2,,EVENTOUT, +PortE,PE1,,LPTIM1_IN2,,HRTIM_SCOUT,,,,,UART8_TX,CAN1_TXFD,,,FMC_NBL1,DCMI_D3,,EVENTOUT, +PortE,PE2,TRACECLK,,SAI1_CK1,,,SPI4_SCK,SAI1_MCLK_A,,SAI4_MCLK_A,QUADSPI_BK1_IO2,SAI4_CK1,ETH_MII_TXD3,FMC_A23,,,EVENTOUT, +PortE,PE3,TRACED0,,,,TIM15_BKIN,,SAI1_SD_B,,SAI4_SD_B,,,,FMC_A19,,,EVENTOUT, +PortE,PE4,TRACED1,,SAI1_D2,DFSDM_DATIN3,TIM15_CH1N,SPI4_NSS,SAI1_FS_A,,SAI4_FS_A,,SAI4_D2,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT, +PortE,PE5,TRACED2,,SAI1_CK2,DFSDM_CKIN3,TIM15_CH1,SPI4_MISO,SAI1_SCK_A,,SAI4_SCK_A,,SAI4_CK2,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT, +PortE,PE6,TRACED3,TIM1_BKIN2,SAI1_D1,,TIM15_CH2,SPI4_MOSI,SAI1_SD_A,,SAI4_SD_A,SAI4_D1,SAI2_MCK_B,TIM1_BKIN2_COMP12,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT, +PortE,PE7,,TIM1_ETR,,DFSDM_DATIN2,,,,UART7_RX,,,QUADSPI_BK2_IO0,,FMC_D4/FMC_DA4,,,EVENTOUT, +PortE,PE8,,TIM1_CH1N,,DFSDM_CKIN2,,,,UART7_TX,,,QUADSPI_BK2_IO1,,FMC_D5/FMC_DA5,COMP_2_OUT,,EVENTOUT, +PortE,PE9,,TIM1_CH1,,DFSDM_CKOUT,,,,UART7_RTS,,,QUADSPI_BK2_IO2,,FMC_D6/FMC_DA6,,,EVENTOUT, +PortE,PE10,,TIM1_CH2N,,DFSDM_DATIN4,,,,UART7_CTS,,,QUADSPI_BK2_IO3,,FMC_D7/FMC_DA7,,,EVENTOUT, +PortE,PE11,,TIM1_CH2,,DFSDM_CKIN4,,SPI4_NSS,,,,,SAI2_SD_B,,FMC_D8/FMC_DA8,,LCD_G3,EVENTOUT, +PortE,PE12,,TIM1_CH3N,,DFSDM_DATIN5,,SPI4_SCK,,,,,SAI2_SCK_B,,FMC_D9/FMC_DA9,COMP_1_OUT,LCD_B4,EVENTOUT, +PortE,PE13,,TIM1_CH3,,DFSDM_CKIN5,,SPI4_MISO,,,,,SAI2_FS_B,,FMC_D10/FMC_DA10,COMP_2_OUT,LCD_DE,EVENTOUT, +PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCK_B,,FMC_D11/FMC_DA11,,LCD_CLK,EVENTOUT, +PortE,PE15,,TIM1_BKIN,,,,HDMI__TIM1_BKIN,,,,,,,FMC_D12/FMC_DA12,TIM1_BKIN_COMP12,LCD_R7,EVENTOUT, +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT, +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT, +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT, +PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT, +PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT, +PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT, +PortF,PF6,,TIM16_CH1,,,,SPI5_NSS,SAI1_SD_B,UART7_RX,SAI4_SD_B,QUADSPI_BK1_IO3,,,,,,EVENTOUT, +PortF,PF7,,TIM17_CH1,,,,SPI5_SCK,SAI1_MCLK_B,UART7_TX,SAI4_MCLK_B,QUADSPI_BK1_IO2,,,,,,EVENTOUT, +PortF,PF8,,TIM16_CH1N,,,,SPI5_MISO,SAI1_SCK_B,UART7_RTS,SAI4_SCK_B,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT, +PortF,PF9,,TIM17_CH1N,,,,SPI5_MOSI,SAI1_FS_B,UART7_CTS,SAI4_FS_B,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT, +PortF,PF10,,TIM16_BKIN,SAI1_D3,,,,,,,QUADSPI_CLK,SAI4_D3,,,DCMI_D11,LCD_DE,EVENTOUT, +PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,DCMI_D12,,EVENTOUT, +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT, +PortF,PF13,,,,DFSDM_DATIN6,I2C4_SMBA,,,,,,,,FMC_A7,,,EVENTOUT, +PortF,PF14,,,,DFSDM_CKIN6,I2C4_SCL,,,,,,,,FMC_A8,,,EVENTOUT, +PortF,PF15,,,,,I2C4_SDA,,,,,,,,FMC_A9,,,EVENTOUT, +PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT, +PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT, +PortG,PG2,,,,TIM8_BKIN,,,,,,,,TIM8_BKIN_COMP12,FMC_A12,,,EVENTOUT, +PortG,PG3,,,,TIM8_BKIN2,,,,,,,,TIM8_BKIN2_COMP12,FMC_A13,,,EVENTOUT, +PortG,PG4,,TIM1_BKIN2,,,,,,,,,,TIM1_BKIN2_COMP12,FMC_A14/FMC_BA0,,,EVENTOUT, +PortG,PG5,,TIM1_ETR,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT, +PortG,PG6,,TIM17_BKIN,HRTIM_CHE1,,,,,,,,QUADSPI_BK1_NCS,,FMC_NE3,DCMI_D12,LCD_R7,EVENTOUT, +PortG,PG7,,,HRTIM_CHE2,,,,SAI1_MCLK_A,USART6_CK,,,,,FMC_INT,DCMI_D13,LCD_CLK,EVENTOUT, +PortG,PG8,,,,TIM8_ETR,,SPI6_NSS,,USART6_RTS,SPDIFRX_IN2,,,ETH_PPS_OUT,FMC_SDCLK,,LCD_G7,EVENTOUT, +PortG,PG9,,,,,,SPI1_MISO/I2S1_SDI,,USART6_RX,SPDIFRX_IN3,QUADSPI_BK2_IO2,SAI2_FS_B,,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT, +PortG,PG10,,,HRTIM_FLT5,,,SPI1_NSS/I2S1_WS,,,,LCD_G3,SAI2_SD_B,,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT, +PortG,PG11,,,HRTIM_EEV4,,,SPI1_SCK/I2S1_CK,,,SPDIFRX_IN0,,SDMMC2_D2,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DCMI_D3,LCD_B3,EVENTOUT, +PortG,PG12,,LPTIM1_IN1,HRTIM_EEV5,,,SPI6_MISO,,USART6_RTS,SPDIFRX_IN1,LCD_B4,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_NE4,,LCD_B1,EVENTOUT, +PortG,PG13,TRACED0,LPTIM1_OUT,HRTIM_EEV10,,,SPI6_SCK,,USART6_CTS_NSS,,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,LCD_R0,EVENTOUT, +PortG,PG14,TRACED1,LPTIM1_ETR,,,,SPI6_MOSI,,USART6_TX,,QUADSPI_BK2_IO3,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,LCD_B0,EVENTOUT, +PortG,PG15,,,,,,,,USART6_CTS_NSS,,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH2,,LPTIM1_IN2,,,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT, +PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT, +PortH,PH4,,,,,I2C2_SCL,,,,,LCD_G5,OTG_HS_ULPI_NXT,,,,LCD_G4,EVENTOUT, +PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT, +PortH,PH6,,,TIM12_CH1,,I2C2_SMBA,SPI5_SCK,,,,,,ETH_MII_RXD2,FMC_SDNE1,DCMI_D8,,EVENTOUT, +PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,EVENTOUT, +PortH,PH8,,,TIM5_ETR,,I2C3_SDA,,,,,,,,FMC_D16,DCMI_HSYNC,LCD_R2,EVENTOUT, +PortH,PH9,,,TIM12_CH2,,I2C3_SMBA,,,,,,,,FMC_D17,DCMI_D0,LCD_R3,EVENTOUT, +PortH,PH10,,,TIM5_CH1,,I2C4_SMBA,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT, +PortH,PH11,,,TIM5_CH2,,I2C4_SCL,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT, +PortH,PH12,,,TIM5_CH3,,I2C4_SDA,,,,,,,,FMC_D20,DCMI_D3,LCD_R6,EVENTOUT, +PortH,PH13,,,,TIM8_CH1N,,,,,UART4_TX,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT, +PortH,PH14,,,,TIM8_CH2N,,,,,UART4_RX,CAN1_RX,,,FMC_D22,DCMI_D4,LCD_G3,EVENTOUT, +PortH,PH15,,,,TIM8_CH3N,,,,,,CAN1_TXFD,,,FMC_D23,DCMI_D11,LCD_G4,EVENTOUT, +PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,CAN1_RXFD,,,FMC_D24,DCMI_D13,LCD_G5,EVENTOUT, +PortI,PI1,,,,TIM8_BKIN2,,SPI2_SCK/I2S2_CK,,,,,,TIM8_BKIN2_COMP12,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT, +PortI,PI2,,,,TIM8_CH4,,SPI2_MISO/I2S2_SDI,,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT, +PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SDO,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT, +PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCK_A,TIM8_BKIN_COMP12,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT, +PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT, +PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT, +PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,DCMI_D7,LCD_B7,EVENTOUT, +PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI9,,,,,,,,,UART4_RX,CAN1_RX,,,FMC_D30,,LCD_VSYNC,EVENTOUT, +PortI,PI10,,,,,,,,,,CAN1_RXFD,,ETH_MII_RX_ER,FMC_D31,,LCD_HSYNC,EVENTOUT, +PortI,PI11,,,,,,,,,,LCD_G6,OTG_HS_ULPI_DIR,,,,,EVENTOUT, +PortI,PI12,,,,,,,,,,,,ETH_TX_ER,,,LCD_HSYNC,EVENTOUT, +PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT, +PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT, +PortI,PI15,,,,,,,,,,LCD_G2,,,,,LCD_R0,EVENTOUT, +PortJ,PJ0,,,,,,,,,,LCD_R7,,,,,LCD_R1,EVENTOUT, +PortJ,PJ1,,,,,,,,,,,,,,,LCD_R2,EVENTOUT, +PortJ,PJ2,,,,,,,,,,,,,,,LCD_R3,EVENTOUT, +PortJ,PJ3,,,,,,,,,,,,,,,LCD_R4,EVENTOUT, +PortJ,PJ4,,,,,,,,,,,,,,,LCD_R5,EVENTOUT, +PortJ,PJ5,,,,,,,,,,,,,,,LCD_R6,EVENTOUT, +PortJ,PJ6,,,,TIM8_CH2,,,,,,,,,,,LCD_R7,EVENTOUT, +PortJ,PJ7,TRGIN,,,TIM8_CH2N,,,,,,,,,,,LCD_G0,EVENTOUT, +PortJ,PJ8,,TIM1_CH3N,,TIM8_CH1,,,,,UART8_TX,,,,,,LCD_G1,EVENTOUT, +PortJ,PJ9,,TIM1_CH3,,TIM8_CH1N,,,,,UART8_RX,,,,,,LCD_G2,EVENTOUT, +PortJ,PJ10,,TIM1_CH2N,,TIM8_CH2,,SPI5_MOSI,,,,,,,,,LCD_G3,EVENTOUT, +PortJ,PJ11,,TIM1_CH2,,TIM8_CH2N,,SPI5_MISO,,,,,,,,,LCD_G4,EVENTOUT, +PortJ,PJ12,TRGOUT,,,,,,,,,LCD_G3,,,,,LCD_B0,EVENTOUT, +PortJ,PJ13,,,,,,,,,,LCD_B4,,,,,LCD_B1,EVENTOUT, +PortJ,PJ14,,,,,,,,,,,,,,,LCD_B2,EVENTOUT, +PortJ,PJ15,,,,,,,,,,,,,,,LCD_B3,EVENTOUT, +PortK,PK0,,TIM1_CH1N,,TIM8_CH3,,SPI5_SCK,,,,,,,,,LCD_G5,EVENTOUT, +PortK,PK1,,TIM1_CH1,,TIM8_CH3N,,SPI5_NSS,,,,,,,,,LCD_G6,EVENTOUT, +PortK,PK2,,TIM1_BKIN,,TIM8_BKIN,,,,,,,TIM8_BKIN_COMP12,TIM1_BKIN_COMP12,,,LCD_G7,EVENTOUT, +PortK,PK3,,,,,,,,,,,,,,,LCD_B4,EVENTOUT, +PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT, +PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT, +PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT, +PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT, From e22ef277b89389ed0a3e4317081b5e913aacdd98 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 9 Mar 2018 14:31:34 +1100 Subject: [PATCH 411/828] lib/stm32lib: Update library to include support for STM32H7 MCUs. Now points to the branch: work-F4-1.16.0+F7-1.7.0+H7-1.2.0+L4-1.8.1 --- lib/stm32lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/stm32lib b/lib/stm32lib index d2bcfda543..000df50c23 160000 --- a/lib/stm32lib +++ b/lib/stm32lib @@ -1 +1 @@ -Subproject commit d2bcfda543d3b99361e44112aca929225bdcc07f +Subproject commit 000df50c233083c7bea05d1fed6fa191a65694bb From 8522874167ea1b38f4041d209d1cab41bc3bc7e3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 9 Mar 2018 15:07:33 +1100 Subject: [PATCH 412/828] stm32/boards: Add stm32h743.ld linker script. --- ports/stm32/boards/stm32h743.ld | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 ports/stm32/boards/stm32h743.ld diff --git a/ports/stm32/boards/stm32h743.ld b/ports/stm32/boards/stm32h743.ld new file mode 100644 index 0000000000..63c160c862 --- /dev/null +++ b/ports/stm32/boards/stm32h743.ld @@ -0,0 +1,32 @@ +/* + GNU linker script for STM32H743 +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 128K /* sector 0, 128K */ + FLASH_FS (r) : ORIGIN = 0x08020000, LENGTH = 128K /* sector 1, 128K */ + FLASH_TEXT (rx) : ORIGIN = 0x08040000, LENGTH = 1792K /* sectors 6*128 + 8*128 */ + DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* Used for storage cache */ + RAM (xrw) : ORIGIN = 0x24000000, LENGTH = 512K /* AXI SRAM */ +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define tho top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* define common sections and symbols */ +INCLUDE common.ld + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x2407C000; /* tunable */ From fabfacf3d714bffd253b52345c48ff974012ae87 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Wed, 21 Feb 2018 00:35:05 +0200 Subject: [PATCH 413/828] stm32/boards: Add new NUCLEO_H743ZI board configuration files. USB serial and mass storage works, and the REPL is also available via the UART through the on-board ST-LINK. --- ports/stm32/boards/NUCLEO_H743ZI/board_init.c | 15 + .../boards/NUCLEO_H743ZI/mpconfigboard.h | 57 +++ .../boards/NUCLEO_H743ZI/mpconfigboard.mk | 6 + ports/stm32/boards/NUCLEO_H743ZI/pins.csv | 59 +++ .../boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h | 434 ++++++++++++++++++ 5 files changed, 571 insertions(+) create mode 100644 ports/stm32/boards/NUCLEO_H743ZI/board_init.c create mode 100644 ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h create mode 100644 ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk create mode 100644 ports/stm32/boards/NUCLEO_H743ZI/pins.csv create mode 100644 ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h diff --git a/ports/stm32/boards/NUCLEO_H743ZI/board_init.c b/ports/stm32/boards/NUCLEO_H743ZI/board_init.c new file mode 100644 index 0000000000..1a6006c280 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H743ZI/board_init.c @@ -0,0 +1,15 @@ +#include STM32_HAL_H + +void NUCLEO_H743ZI_board_early_init(void) { + GPIO_InitTypeDef GPIO_InitStructure; + + __HAL_RCC_GPIOG_CLK_ENABLE(); + + // Turn off the USB switch + GPIO_InitStructure.Pin = GPIO_PIN_6; + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStructure.Pull = GPIO_PULLDOWN; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); + HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_RESET); +} diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h new file mode 100644 index 0000000000..4fe41e0a1b --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h @@ -0,0 +1,57 @@ +#define MICROPY_HW_BOARD_NAME "NUCLEO_H743ZI" +#define MICROPY_HW_MCU_NAME "STM32H743" + +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_ADC (0) +#define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) + +#define MICROPY_BOARD_EARLY_INIT NUCLEO_H743ZI_board_early_init +void NUCLEO_H743ZI_board_early_init(void); + +// The board has an 8MHz HSE, the following gives 400MHz CPU speed +#define MICROPY_HW_CLK_PLLM (4) +#define MICROPY_HW_CLK_PLLN (400) +#define MICROPY_HW_CLK_PLLP (2) +#define MICROPY_HW_CLK_PLLQ (4) +#define MICROPY_HW_CLK_PLLR (2) + +// 4 wait states +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 + +// UART config +#define MICROPY_HW_UART3_TX (pin_D8) +#define MICROPY_HW_UART3_RX (pin_D9) +#define MICROPY_HW_UART_REPL PYB_UART_3 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +//#define MICROPY_HW_I2C1_SCL (pin_B8) +//#define MICROPY_HW_I2C1_SDA (pin_B9) +//#define MICROPY_HW_I2C3_SCL (pin_H7) +//#define MICROPY_HW_I2C3_SDA (pin_H8) + +// SPI +//#define MICROPY_HW_SPI2_NSS (pin_I0) +//#define MICROPY_HW_SPI2_SCK (pin_I1) +//#define MICROPY_HW_SPI2_MISO (pin_B14) +//#define MICROPY_HW_SPI2_MOSI (pin_B15) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_C13) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_B0) // green +#define MICROPY_HW_LED2 (pin_B7) // blue +#define MICROPY_HW_LED3 (pin_B14) // red +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk new file mode 100644 index 0000000000..82b12cd2da --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = h7 +CMSIS_MCU = STM32H743xx +MICROPY_FLOAT_IMPL = double +AF_FILE = boards/stm32h743_af.csv +LD_FILE = boards/stm32h743.ld +TEXT_ADDR = 0x08040000 diff --git a/ports/stm32/boards/NUCLEO_H743ZI/pins.csv b/ports/stm32/boards/NUCLEO_H743ZI/pins.csv new file mode 100644 index 0000000000..b0d225368c --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H743ZI/pins.csv @@ -0,0 +1,59 @@ +A0,PA0 +A1,PF10 +A2,PF9 +A3,PF8 +A4,PF7 +A5,PF6 +D0,PC7 +D1,PC6 +D2,PG6 +D3,PB4 +D4,PG7 +D5,PA8 +D6,PH6 +D7,PI3 +D8,PI2 +D9,PA15 +D10,PI0 +D11,PB15 +D12,PB14 +D13,PI1 +D14,PB9 +D15,PB8 +LED1,PB0 +LED2,PB7 +LED3,PB14 +SW,PC13 +TP1,PH2 +TP2,PI8 +TP3,PH15 +AUDIO_INT,PD6 +AUDIO_SDA,PH8 +AUDIO_SCL,PH7 +EXT_SDA,PB9 +EXT_SCL,PB8 +EXT_RST,PG3 +SD_D0,PG9 +SD_D1,PG10 +SD_D2,PB3 +SD_D3,PB4 +SD_CK,PD6 +SD_CMD,PD7 +SD_SW,PI15 +LCD_BL_CTRL,PK3 +LCD_INT,PI13 +LCD_SDA,PH8 +LCD_SCL,PH7 +OTG_FS_POWER,PD5 +OTG_FS_OVER_CURRENT,PD4 +OTG_HS_OVER_CURRENT,PE3 +USB_VBUS,PJ12 +USB_ID,PA8 +USB_DM,PA11 +USB_DP,PA12 +UART1_TX,PA9 +UART1_RX,PA10 +UART5_TX,PC12 +UART5_RX,PD2 +UART3_TX,PD8 +UART3_RX,PD9 diff --git a/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h new file mode 100644 index 0000000000..89421d30b7 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h @@ -0,0 +1,434 @@ +/** + ****************************************************************************** + * @file stm32h7xx_hal_conf_template.h + * @author MCD Application Team + * @version V1.2.0 + * @date 29-December-2017 + * @brief HAL configuration template file. + * This file should be copied to the application folder and renamed + * to stm32h7xx_hal_conf.h. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32H7xx_HAL_CONF_H +#define __STM32H7xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CEC_MODULE_ENABLED +#define HAL_COMP_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_CRC_MODULE_ENABLED +#define HAL_CRYP_MODULE_ENABLED +#define HAL_DAC_MODULE_ENABLED +#define HAL_DCMI_MODULE_ENABLED +#define HAL_DFSDM_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_DMA2D_MODULE_ENABLED +#define HAL_ETH_MODULE_ENABLED +#define HAL_FDCAN_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_GPIO_MODULE_ENABLED +#define HAL_HASH_MODULE_ENABLED +#define HAL_HCD_MODULE_ENABLED +#define HAL_HRTIM_MODULE_ENABLED +#define HAL_HSEM_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_MODULE_ENABLED +#define HAL_IRDA_MODULE_ENABLED +#define HAL_IWDG_MODULE_ENABLED +#define HAL_JPEG_MODULE_ENABLED +#define HAL_LPTIM_MODULE_ENABLED +#define HAL_LTDC_MODULE_ENABLED +#define HAL_MDIOS_MODULE_ENABLED +#define HAL_MDMA_MODULE_ENABLED +#define HAL_MMC_MODULE_ENABLED +#define HAL_NAND_MODULE_ENABLED +#define HAL_NOR_MODULE_ENABLED +#define HAL_OPAMP_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_QSPI_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +#define HAL_SAI_MODULE_ENABLED +#define HAL_SD_MODULE_ENABLED +#define HAL_SDRAM_MODULE_ENABLED +#define HAL_SMARTCARD_MODULE_ENABLED +#define HAL_SMBUS_MODULE_ENABLED +#define HAL_SPDIFRX_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_SRAM_MODULE_ENABLED +#define HAL_SWPMI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +#define HAL_USART_MODULE_ENABLED +#define HAL_WWDG_MODULE_ENABLED + +/* ########################## Oscillator Values adaptation ####################*/ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) +#define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal oscillator (CSI) default value. + * This value is the default CSI value after Reset. + */ +#if !defined (CSI_VALUE) + #define CSI_VALUE ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* CSI_VALUE */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)64000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief External Low Speed oscillator (LSE) value. + * This value is used by the UART, RTC HAL module to compute the system frequency + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External oscillator in Hz*/ +#endif /* LSE_VALUE */ + + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE 12288000U /*!< Value of the External clock in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x0F) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define USE_SD_TRANSCEIVER 1U /*!< use uSD Transceiver */ + +/* ########################### Ethernet Configuration ######################### */ +#define ETH_TX_DESC_CNT 4 /* number of Ethernet Tx DMA descriptors */ +#define ETH_RX_DESC_CNT 4 /* number of Ethernet Rx DMA descriptors */ + +#define ETH_MAC_ADDR0 ((uint8_t)0x02) +#define ETH_MAC_ADDR1 ((uint8_t)0x00) +#define ETH_MAC_ADDR2 ((uint8_t)0x00) +#define ETH_MAC_ADDR3 ((uint8_t)0x00) +#define ETH_MAC_ADDR4 ((uint8_t)0x00) +#define ETH_MAC_ADDR5 ((uint8_t)0x00) + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## SPI peripheral configuration ########################## */ +/** + * @brief Used to activate CRC feature inside HAL SPI Driver + * Activated (1U): CRC code is compiled within HAL SPI driver + * Deactivated (0U): CRC code excluded from HAL SPI driver + */ + +#define USE_SPI_CRC 1U + + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32h7xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32h7xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32h7xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32h7xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32h7xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32h7xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DFSDM_MODULE_ENABLED + #include "stm32h7xx_hal_dfsdm.h" +#endif /* HAL_DFSDM_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32h7xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32h7xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32h7xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_FDCAN_MODULE_ENABLED + #include "stm32h7xx_hal_fdcan.h" +#endif /* HAL_FDCAN_MODULE_ENABLED */ + +#ifdef HAL_CEC_MODULE_ENABLED + #include "stm32h7xx_hal_cec.h" +#endif /* HAL_CEC_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED + #include "stm32h7xx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32h7xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32h7xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32h7xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32h7xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_HRTIM_MODULE_ENABLED + #include "stm32h7xx_hal_hrtim.h" +#endif /* HAL_HRTIM_MODULE_ENABLED */ + +#ifdef HAL_HSEM_MODULE_ENABLED + #include "stm32h7xx_hal_hsem.h" +#endif /* HAL_HSEM_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32h7xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32h7xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32h7xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32h7xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32h7xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32h7xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_JPEG_MODULE_ENABLED + #include "stm32h7xx_hal_jpeg.h" +#endif /* HAL_JPEG_MODULE_ENABLED */ + +#ifdef HAL_MDIOS_MODULE_ENABLED + #include "stm32h7xx_hal_mdios.h" +#endif /* HAL_MDIOS_MODULE_ENABLED */ + +#ifdef HAL_MDMA_MODULE_ENABLED + #include "stm32h7xx_hal_mdma.h" +#endif /* HAL_MDMA_MODULE_ENABLED */ + +#ifdef HAL_MMC_MODULE_ENABLED + #include "stm32h7xx_hal_mmc.h" +#endif /* HAL_MMC_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED +#include "stm32h7xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED +#include "stm32h7xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_OPAMP_MODULE_ENABLED +#include "stm32h7xx_hal_opamp.h" +#endif /* HAL_OPAMP_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32h7xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32h7xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32h7xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32h7xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32h7xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32h7xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32h7xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32h7xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_SPDIFRX_MODULE_ENABLED + #include "stm32h7xx_hal_spdifrx.h" +#endif /* HAL_SPDIFRX_MODULE_ENABLED */ + +#ifdef HAL_SWPMI_MODULE_ENABLED + #include "stm32h7xx_hal_swpmi.h" +#endif /* HAL_SWPMI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32h7xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32h7xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32h7xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32h7xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32h7xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED + #include "stm32h7xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32h7xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32h7xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32h7xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32H7xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ From b8d09b9bef72ffbbe4d66c612d421980cd523092 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Wed, 21 Feb 2018 00:35:42 +0200 Subject: [PATCH 414/828] stm32/Makefile: Add settings to support H7 MCUs. --- ports/stm32/Makefile | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 0f836f2455..5e4ec9f6f8 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -53,7 +53,7 @@ INC += -I$(USBDEV_DIR)/core/inc -I$(USBDEV_DIR)/class/inc CFLAGS_CORTEX_M = -mthumb # Select hardware floating-point support -ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F767xx STM32F769xx)) +ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F767xx STM32F769xx STM32H743xx)) CFLAGS_CORTEX_M += -mfpu=fpv5-d16 -mfloat-abi=hard else CFLAGS_CORTEX_M += -mfpu=fpv4-sp-d16 -mfloat-abi=hard @@ -63,6 +63,7 @@ endif CFLAGS_MCU_f4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 -DMCU_SERIES_F4 CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 -DMCU_SERIES_F7 CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 -DMCU_SERIES_L4 +CFLAGS_MCU_h7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_EXTRA) CFLAGS += -D$(CMSIS_MCU) @@ -250,11 +251,11 @@ SRC_O = \ startup_stm32.o \ gchelper.o \ +$(BUILD)/$(HAL_DIR)/Src/%.o: CFLAGS += -fno-strict-aliasing SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ hal.c \ hal_adc.c \ hal_adc_ex.c \ - hal_can.c \ hal_cortex.c \ hal_dac.c \ hal_dac_ex.c \ @@ -280,6 +281,12 @@ SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ ll_usb.c \ ) +ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32H743xx)) + SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_fdcan.c) +else + SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_can.c) +endif + SRC_USBDEV = $(addprefix $(USBDEV_DIR)/,\ core/src/usbd_core.c \ core/src/usbd_ctlreq.c \ From 81f8f5f16395bee89bb78a845a38e98e67b78fe4 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Thu, 22 Feb 2018 14:05:00 +0200 Subject: [PATCH 415/828] stm32/flash: Add flash support for H7 MCUs. --- ports/stm32/flash.c | 34 +++++++++++++++++++++++++++++++++- ports/stm32/flashbdev.c | 8 ++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/ports/stm32/flash.c b/ports/stm32/flash.c index 10e1d2eff1..4042785fa2 100644 --- a/ports/stm32/flash.c +++ b/ports/stm32/flash.c @@ -68,15 +68,25 @@ static const flash_layout_t flash_layout[] = { { (uint32_t)FLASH_BASE, (uint32_t)FLASH_PAGE_SIZE, 512 }, }; +#elif defined(STM32H7) + +static const flash_layout_t flash_layout[] = { + { 0x08000000, 0x20000, 8 }, +}; + #else #error Unsupported processor #endif -#if defined(MCU_SERIES_L4) +#if defined(MCU_SERIES_L4) || defined(STM32H7) // get the bank of a given flash address static uint32_t get_bank(uint32_t addr) { + #if defined(STM32H7) + if (READ_BIT(FLASH->OPTCR, FLASH_OPTCR_SWAP_BANK) == 0) { + #else if (READ_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_FB_MODE) == 0) { + #endif // no bank swap if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) { return FLASH_BANK_1; @@ -93,6 +103,7 @@ static uint32_t get_bank(uint32_t addr) { } } +#if defined(MCU_SERIES_L4) // get the page of a given flash address static uint32_t get_page(uint32_t addr) { if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) { @@ -103,6 +114,7 @@ static uint32_t get_page(uint32_t addr) { return (addr - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE; } } +#endif #endif @@ -153,12 +165,19 @@ void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) EraseInitStruct.NbPages = get_page(flash_dest + 4 * num_word32 - 1) - EraseInitStruct.Page + 1;; #else // Clear pending flags (if any) + #if defined(STM32H7) + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS_BANK1 | FLASH_FLAG_ALL_ERRORS_BANK2); + #else __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); + #endif // erase the sector(s) EraseInitStruct.TypeErase = TYPEERASE_SECTORS; EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V + #if defined(STM32H7) + EraseInitStruct.Banks = get_bank(flash_dest); + #endif EraseInitStruct.Sector = flash_get_sector_info(flash_dest, NULL, NULL); EraseInitStruct.NbSectors = flash_get_sector_info(flash_dest + 4 * num_word32 - 1, NULL, NULL) - EraseInitStruct.Sector + 1; #endif @@ -224,6 +243,19 @@ void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) } } + #elif defined(STM32H7) + + // program the flash 256 bits at a time + for (int i = 0; i < num_word32 / 8; i++) { + if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, flash_dest, (uint64_t)(uint32_t)src) != HAL_OK) { + // error occurred during flash write + HAL_FLASH_Lock(); // lock the flash + return; + } + flash_dest += 32; + src += 8; + } + #else // program the flash word by word diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c index 49fe5c6964..ec2e4f212d 100644 --- a/ports/stm32/flashbdev.c +++ b/ports/stm32/flashbdev.c @@ -85,6 +85,14 @@ STATIC byte flash_cache_mem[0x4000] __attribute__((aligned(4))); // 16k #define FLASH_MEM_SEG1_START_ADDR (0x08008000) // sector 1 #define FLASH_MEM_SEG1_NUM_BLOCKS (192) // sectors 1,2,3: 32k+32k+32=96k +#elif defined(STM32H743xx) + +// The STM32H743 flash sectors are 128K +#define CACHE_MEM_START_ADDR (0x20000000) // DTCM data RAM, 128k +#define FLASH_SECTOR_SIZE_MAX (0x20000) // 128k max +#define FLASH_MEM_SEG1_START_ADDR (0x08020000) // sector 1 +#define FLASH_MEM_SEG1_NUM_BLOCKS (256) // Sector 1: 128k / 512b = 256 blocks + #elif defined(STM32L475xx) || defined(STM32L476xx) extern uint8_t _flash_fs_start; From 2e93d4167d6f923e9bb8ffc59478c225e756ecf2 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Thu, 22 Feb 2018 20:31:38 +0200 Subject: [PATCH 416/828] stm32/system_stm32: Add H7 MCU system initialisation. --- ports/stm32/system_stm32.c | 150 ++++++++++++++++++++++++++++++++----- 1 file changed, 132 insertions(+), 18 deletions(-) diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c index b71a03181a..bd25a149b4 100644 --- a/ports/stm32/system_stm32.c +++ b/ports/stm32/system_stm32.c @@ -135,6 +135,17 @@ const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; const uint32_t MSIRangeTable[12] = {100000, 200000, 400000, 800000, 1000000, 2000000, \ 4000000, 8000000, 16000000, 24000000, 32000000, 48000000}; +#elif defined(STM32H7) + +#define CONFIG_RCC_CR_1ST (RCC_CR_HSION) +#define CONFIG_RCC_CR_2ND (~0xEAF6ED7F) +#define CONFIG_RCC_PLLCFGR (0x00000000) + +#define SRAM_BASE D1_AXISRAM_BASE +#define FLASH_BASE FLASH_BANK1_BASE +uint32_t SystemD2Clock = 64000000; +const uint8_t D1CorePrescTable[16] = {0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 6, 7, 8, 9}; + #else #error Unknown processor #endif @@ -216,16 +227,53 @@ void SystemInit(void) /* Reset PLLCFGR register */ RCC->PLLCFGR = CONFIG_RCC_PLLCFGR; + #if defined(STM32H7) + /* Reset D1CFGR register */ + RCC->D1CFGR = 0x00000000; + + /* Reset D2CFGR register */ + RCC->D2CFGR = 0x00000000; + + /* Reset D3CFGR register */ + RCC->D3CFGR = 0x00000000; + + /* Reset PLLCKSELR register */ + RCC->PLLCKSELR = 0x00000000; + + /* Reset PLL1DIVR register */ + RCC->PLL1DIVR = 0x00000000; + + /* Reset PLL1FRACR register */ + RCC->PLL1FRACR = 0x00000000; + + /* Reset PLL2DIVR register */ + RCC->PLL2DIVR = 0x00000000; + + /* Reset PLL2FRACR register */ + RCC->PLL2FRACR = 0x00000000; + + /* Reset PLL3DIVR register */ + RCC->PLL3DIVR = 0x00000000; + + /* Reset PLL3FRACR register */ + RCC->PLL3FRACR = 0x00000000; + #endif + /* Reset HSEBYP bit */ RCC->CR &= (uint32_t)0xFFFBFFFF; /* Disable all interrupts */ #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) RCC->CIR = 0x00000000; - #elif defined(MCU_SERIES_L4) + #elif defined(MCU_SERIES_L4) || defined(STM32H7) RCC->CIER = 0x00000000; #endif + #if defined(STM32H7) + /* Change the switch matrix read issuing capability to 1 for the AXI SRAM target (Target 7) */ + *((__IO uint32_t*)0x51008108) = 0x00000001; + #endif + /* Configure the Vector Table location add offset address ------------------*/ #ifdef VECT_TAB_SRAM SCB->VTOR = SRAM1_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */ @@ -319,26 +367,44 @@ void SystemInit(void) */ void SystemClock_Config(void) { - RCC_ClkInitTypeDef RCC_ClkInitStruct; - RCC_OscInitTypeDef RCC_OscInitStruct; + RCC_ClkInitTypeDef RCC_ClkInitStruct; + RCC_OscInitTypeDef RCC_OscInitStruct; + #if defined(STM32H7) + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; + #endif - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) - /* Enable Power Control clock */ - __PWR_CLK_ENABLE(); + #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) || defined(STM32H7) - /* The voltage scaling allows optimizing the power consumption when the device is - clocked below the maximum system frequency, to update the voltage scaling value - regarding system frequency refer to product datasheet. */ - __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + /* Enable Power Control clock */ + #if defined(STM32H7) + MODIFY_REG(PWR->CR3, PWR_CR3_SCUEN, 0); + #else + __PWR_CLK_ENABLE(); + #endif + + /* The voltage scaling allows optimizing the power consumption when the device is + clocked below the maximum system frequency, to update the voltage scaling value + regarding system frequency refer to product datasheet. */ + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); #elif defined(MCU_SERIES_L4) // Configure LSE Drive Capability __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW); #endif + #if defined(STM32H7) + // Wait for PWR_FLAG_VOSRDY + while ((PWR->D3CR & (PWR_D3CR_VOSRDY)) != PWR_D3CR_VOSRDY) { + } + #endif + /* Enable HSE Oscillator and activate PLL with HSE as source */ - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) || defined(STM32H7) RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; + RCC_OscInitStruct.HSIState = RCC_HSI_OFF; + #if defined(STM32H7) + RCC_OscInitStruct.CSIState = RCC_CSI_OFF; + #endif RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; #elif defined(MCU_SERIES_L4) RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI; @@ -352,6 +418,9 @@ void SystemClock_Config(void) /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */ RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); + #if defined(STM32H7) + RCC_ClkInitStruct.ClockType |= (RCC_CLOCKTYPE_D3PCLK1 | RCC_CLOCKTYPE_D1PCLK1); + #endif RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; #if defined(MICROPY_HW_CLK_LAST_FREQ) && MICROPY_HW_CLK_LAST_FREQ @@ -401,23 +470,54 @@ void SystemClock_Config(void) RCC_OscInitStruct.PLL.PLLN = MICROPY_HW_CLK_PLLN; RCC_OscInitStruct.PLL.PLLP = MICROPY_HW_CLK_PLLP; RCC_OscInitStruct.PLL.PLLQ = MICROPY_HW_CLK_PLLQ; - #if defined(MCU_SERIES_L4) + #if defined(MCU_SERIES_L4) || defined(STM32H7) RCC_OscInitStruct.PLL.PLLR = MICROPY_HW_CLK_PLLR; #endif - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + #if defined(STM32H7) + RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_1; + RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE; + RCC_OscInitStruct.PLL.PLLFRACN = 0; + #endif + #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; #elif defined(MCU_SERIES_L4) + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; + #elif defined(STM32H7) + RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2; + RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; + RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; + RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; + RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; #endif #endif - if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) - { - __fatal_error("HAL_RCC_OscConfig"); - } + + if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { + __fatal_error("HAL_RCC_OscConfig"); + } + +#if defined(STM32H7) + /* PLL3 for USB Clock */ + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USB; + PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLL3; + PeriphClkInitStruct.PLL3.PLL3M = 4; + PeriphClkInitStruct.PLL3.PLL3N = 120; + PeriphClkInitStruct.PLL3.PLL3P = 2; + PeriphClkInitStruct.PLL3.PLL3Q = 5; + PeriphClkInitStruct.PLL3.PLL3R = 2; + PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_1; + PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOWIDE; + PeriphClkInitStruct.PLL3.PLL3FRACN = 0; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { + __fatal_error("HAL_RCCEx_PeriphCLKConfig"); + } +#endif #if defined(MCU_SERIES_F7) /* Activate the OverDrive to reach the 200 MHz Frequency */ @@ -436,6 +536,20 @@ void SystemClock_Config(void) __fatal_error("HAL_RCC_ClockConfig"); } +#if defined(STM32H7) + /* Activate CSI clock mandatory for I/O Compensation Cell*/ + __HAL_RCC_CSI_ENABLE() ; + + /* Enable SYSCFG clock mandatory for I/O Compensation Cell */ + __HAL_RCC_SYSCFG_CLK_ENABLE() ; + + /* Enable the I/O Compensation Cell */ + HAL_EnableCompensationCell(); + + /* Enable the USB voltage level detector */ + HAL_PWREx_EnableUSBVoltageDetector(); +#endif + #if defined(MCU_SERIES_F7) // The DFU bootloader changes the clocksource register from its default power // on reset value, so we set it back here, so the clocksources are the same @@ -486,7 +600,7 @@ void SystemClock_Config(void) } void HAL_MspInit(void) { -#if defined(MCU_SERIES_F7) +#if defined(MCU_SERIES_F7) || defined(STM32H7) /* Enable I-Cache */ SCB_EnableICache(); From 3f86fbcb079f21805e5988610d13ebed0b3b884c Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 23 Feb 2018 02:50:21 +0200 Subject: [PATCH 417/828] stm32/mphalport: Use GPIO BSRRL/BSRRH registers for H7 MCUs. --- ports/stm32/mphalport.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h index b0387e6447..c3d280b408 100644 --- a/ports/stm32/mphalport.h +++ b/ports/stm32/mphalport.h @@ -45,8 +45,13 @@ static inline mp_uint_t mp_hal_ticks_cpu(void) { #define mp_hal_pin_input(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0) #define mp_hal_pin_output(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0) #define mp_hal_pin_open_drain(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_OPEN_DRAIN, MP_HAL_PIN_PULL_NONE, 0) +#if defined(STM32H7) +#define mp_hal_pin_high(p) (((p)->gpio->BSRRL) = (p)->pin_mask) +#define mp_hal_pin_low(p) (((p)->gpio->BSRRH) = (p)->pin_mask) +#else #define mp_hal_pin_high(p) (((p)->gpio->BSRR) = (p)->pin_mask) #define mp_hal_pin_low(p) (((p)->gpio->BSRR) = ((p)->pin_mask << 16)) +#endif #define mp_hal_pin_od_low(p) mp_hal_pin_low(p) #define mp_hal_pin_od_high(p) mp_hal_pin_high(p) #define mp_hal_pin_read(p) (((p)->gpio->IDR >> (p)->pin) & 1) From a863c60439e928a98709f37c95538bbec43c1283 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 23 Feb 2018 18:53:00 +0200 Subject: [PATCH 418/828] stm32/wdt: Add WDT support for H7 MCUs. --- ports/stm32/wdt.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/stm32/wdt.c b/ports/stm32/wdt.c index 2b4967a434..8df7b47684 100644 --- a/ports/stm32/wdt.c +++ b/ports/stm32/wdt.c @@ -29,6 +29,10 @@ #include "py/runtime.h" #include "wdt.h" +#if defined(STM32H7) +#define IWDG (IWDG1) +#endif + typedef struct _pyb_wdt_obj_t { mp_obj_base_t base; } pyb_wdt_obj_t; From b982b95c18bd5d7ffcc8164b65d70d945844f557 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 23 Feb 2018 18:53:20 +0200 Subject: [PATCH 419/828] stm32/uart: Add UART support for H7 MCUs. --- ports/stm32/uart.c | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index 1e540e50ac..72bc3bb2f4 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -91,8 +91,26 @@ struct _pyb_uart_obj_t { }; STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in); +extern void NORETURN __fatal_error(const char *msg); void uart_init0(void) { + #if defined(STM32H7) + RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit = {0}; + // Configure USART1/6 clock source + RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART16; + RCC_PeriphClkInit.Usart16ClockSelection = RCC_USART16CLKSOURCE_D2PCLK2; + if (HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit) != HAL_OK) { + __fatal_error("HAL_RCCEx_PeriphCLKConfig"); + } + + // Configure USART2/3/4/5/7/8 clock source + RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART234578; + RCC_PeriphClkInit.Usart16ClockSelection = RCC_USART234578CLKSOURCE_D2PCLK1; + if (HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit) != HAL_OK) { + __fatal_error("HAL_RCCEx_PeriphCLKConfig"); + } + #endif + for (int i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(pyb_uart_obj_all)); i++) { MP_STATE_PORT(pyb_uart_obj_all)[i] = NULL; } @@ -365,7 +383,7 @@ int uart_rx_char(pyb_uart_obj_t *self) { return data; } else { // no buffering - #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) + #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) || defined(STM32H7) return self->uart.Instance->RDR & self->char_mask; #else return self->uart.Instance->DR & self->char_mask; @@ -483,7 +501,7 @@ void uart_irq_handler(mp_uint_t uart_id) { uint16_t next_head = (self->read_buf_head + 1) % self->read_buf_len; if (next_head != self->read_buf_tail) { // only read data if room in buf - #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) + #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) || defined(STM32H7) int data = self->uart.Instance->RDR; // clears UART_FLAG_RXNE #else int data = self->uart.Instance->DR; // clears UART_FLAG_RXNE @@ -668,15 +686,28 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const // compute actual baudrate that was configured // (this formula assumes UART_OVERSAMPLING_16) uint32_t actual_baudrate = 0; - #if defined(MCU_SERIES_F7) + #if defined(MCU_SERIES_F7) || defined(STM32H7) UART_ClockSourceTypeDef clocksource = UART_CLOCKSOURCE_UNDEFINED; UART_GETCLOCKSOURCE(&self->uart, clocksource); switch (clocksource) { + #if defined(STM32H7) + case UART_CLOCKSOURCE_D2PCLK1: actual_baudrate = HAL_RCC_GetPCLK1Freq(); break; + case UART_CLOCKSOURCE_D3PCLK1: actual_baudrate = HAL_RCC_GetPCLK1Freq(); break; + case UART_CLOCKSOURCE_D2PCLK2: actual_baudrate = HAL_RCC_GetPCLK2Freq(); break; + #else case UART_CLOCKSOURCE_PCLK1: actual_baudrate = HAL_RCC_GetPCLK1Freq(); break; case UART_CLOCKSOURCE_PCLK2: actual_baudrate = HAL_RCC_GetPCLK2Freq(); break; - case UART_CLOCKSOURCE_HSI: actual_baudrate = HSI_VALUE; break; case UART_CLOCKSOURCE_SYSCLK: actual_baudrate = HAL_RCC_GetSysClockFreq(); break; + #endif + #if defined(STM32H7) + case UART_CLOCKSOURCE_CSI: actual_baudrate = CSI_VALUE; break; + #endif + case UART_CLOCKSOURCE_HSI: actual_baudrate = HSI_VALUE; break; case UART_CLOCKSOURCE_LSE: actual_baudrate = LSE_VALUE; break; + #if defined(STM32H7) + case UART_CLOCKSOURCE_PLL2: + case UART_CLOCKSOURCE_PLL3: + #endif case UART_CLOCKSOURCE_UNDEFINED: break; } #else @@ -906,7 +937,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_readchar_obj, pyb_uart_readchar); // uart.sendbreak() STATIC mp_obj_t pyb_uart_sendbreak(mp_obj_t self_in) { pyb_uart_obj_t *self = self_in; - #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) + #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) || defined(STM32H7) self->uart.Instance->RQR = USART_RQR_SBKRQ; // write-only register #else self->uart.Instance->CR1 |= USART_CR1_SBK; From 0989e0cdffb527527dcf89d835afbde82bf4bdbb Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 23 Feb 2018 18:53:29 +0200 Subject: [PATCH 420/828] stm32/timer: Add Timer support for H7 MCUs. --- ports/stm32/timer.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c index bac63ae920..fa6141634b 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -229,16 +229,22 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { // respective APB clock. See DM00031020 Rev 4, page 115. uint32_t timer_get_source_freq(uint32_t tim_id) { uint32_t source; + uint32_t latency; + RCC_ClkInitTypeDef rcc_init; + + // Get clock config. + HAL_RCC_GetClockConfig(&rcc_init, &latency); + if (tim_id == 1 || (8 <= tim_id && tim_id <= 11)) { // TIM{1,8,9,10,11} are on APB2 source = HAL_RCC_GetPCLK2Freq(); - if ((uint32_t)((RCC->CFGR & RCC_CFGR_PPRE2) >> 3) != RCC_HCLK_DIV1) { + if (rcc_init.APB2CLKDivider != RCC_HCLK_DIV1) { source *= 2; } } else { // TIM{2,3,4,5,6,7,12,13,14} are on APB1 source = HAL_RCC_GetPCLK1Freq(); - if ((uint32_t)(RCC->CFGR & RCC_CFGR_PPRE1) != RCC_HCLK_DIV1) { + if (rcc_init.APB1CLKDivider != RCC_HCLK_DIV1) { source *= 2; } } @@ -690,14 +696,26 @@ STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = { TIM_ENTRY(14, TIM8_TRG_COM_TIM14_IRQn), #endif #if defined(TIM15) + #if defined(STM32H7) + TIM_ENTRY(15, TIM15_IRQn), + #else TIM_ENTRY(15, TIM1_BRK_TIM15_IRQn), #endif + #endif #if defined(TIM16) + #if defined(STM32H7) + TIM_ENTRY(16, TIM16_IRQn), + #else TIM_ENTRY(16, TIM1_UP_TIM16_IRQn), #endif + #endif #if defined(TIM17) + #if defined(STM32H7) + TIM_ENTRY(17, TIM17_IRQn), + #else TIM_ENTRY(17, TIM1_TRG_COM_TIM17_IRQn), #endif + #endif }; #undef TIM_ENTRY From d151adb791df6f3ac6d12431ad6bcad62f730363 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 23 Feb 2018 18:54:09 +0200 Subject: [PATCH 421/828] stm32/modmachine: Support basic H7 MCU features. --- ports/stm32/modmachine.c | 42 ++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index 5a499e3da6..8b2c4e2f61 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -59,6 +59,24 @@ #define RCC_CSR_PORRSTF RCC_CSR_BORRSTF #endif +#if defined(STM32H7) +#define RCC_SR RSR +#define RCC_SR_IWDGRSTF RCC_RSR_IWDG1RSTF +#define RCC_SR_WWDGRSTF RCC_RSR_WWDG1RSTF +#define RCC_SR_PORRSTF RCC_RSR_PORRSTF +#define RCC_SR_BORRSTF RCC_RSR_BORRSTF +#define RCC_SR_PINRSTF RCC_RSR_PINRSTF +#define RCC_SR_RMVF RCC_RSR_RMVF +#else +#define RCC_SR CSR +#define RCC_SR_IWDGRSTF RCC_CSR_IWDGRSTF +#define RCC_SR_WWDGRSTF RCC_CSR_WWDGRSTF +#define RCC_SR_PORRSTF RCC_CSR_PORRSTF +#define RCC_SR_BORRSTF RCC_CSR_BORRSTF +#define RCC_SR_PINRSTF RCC_CSR_PINRSTF +#define RCC_SR_RMVF RCC_CSR_RMVF +#endif + #define PYB_RESET_SOFT (0) #define PYB_RESET_POWER_ON (1) #define PYB_RESET_HARD (2) @@ -80,15 +98,21 @@ void machine_init(void) { reset_cause = PYB_RESET_DEEPSLEEP; PWR->CR1 |= PWR_CR1_CSBF; } else + #elif defined(STM32H7) + if (PWR->CPUCR & PWR_CPUCR_SBF || PWR->CPUCR & PWR_CPUCR_STOPF) { + // came out of standby or stop mode + reset_cause = PYB_RESET_DEEPSLEEP; + PWR->CPUCR |= PWR_CPUCR_CSSF; + } else #endif { // get reset cause from RCC flags - uint32_t state = RCC->CSR; - if (state & RCC_CSR_IWDGRSTF || state & RCC_CSR_WWDGRSTF) { + uint32_t state = RCC->RCC_SR; + if (state & RCC_SR_IWDGRSTF || state & RCC_SR_WWDGRSTF) { reset_cause = PYB_RESET_WDT; - } else if (state & RCC_CSR_PORRSTF || state & RCC_CSR_BORRSTF) { + } else if (state & RCC_SR_PORRSTF || state & RCC_SR_BORRSTF) { reset_cause = PYB_RESET_POWER_ON; - } else if (state & RCC_CSR_PINRSTF) { + } else if (state & RCC_SR_PINRSTF) { reset_cause = PYB_RESET_HARD; } else { // default is soft reset @@ -96,7 +120,7 @@ void machine_init(void) { } } // clear RCC reset flags - RCC->CSR |= RCC_CSR_RMVF; + RCC->RCC_SR |= RCC_SR_RMVF; } void machine_deinit(void) { @@ -217,7 +241,7 @@ STATIC NORETURN mp_obj_t machine_bootloader(void) { HAL_MPU_Disable(); #endif -#if defined(MCU_SERIES_F7) +#if defined(MCU_SERIES_F7) || defined(STM32H7) // arm-none-eabi-gcc 4.9.0 does not correctly inline this // MSP function, so we write it out explicitly here. //__set_MSP(*((uint32_t*) 0x1FF00000)); @@ -487,7 +511,11 @@ STATIC mp_obj_t machine_sleep(void) { // select PLL as system clock source MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_SYSCLKSOURCE_PLLCLK); + #if defined(STM32H7) + while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL1) { + #else while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL) { + #endif } #endif @@ -526,6 +554,8 @@ STATIC mp_obj_t machine_deepsleep(void) { PWR->CSR2 &= ~(PWR_CSR2_EWUP6 | PWR_CSR2_EWUP5 | PWR_CSR2_EWUP4 | PWR_CSR2_EWUP3 | PWR_CSR2_EWUP2 | PWR_CSR2_EWUP1); // clear global wake-up flag PWR->CR2 |= PWR_CR2_CWUPF6 | PWR_CR2_CWUPF5 | PWR_CR2_CWUPF4 | PWR_CR2_CWUPF3 | PWR_CR2_CWUPF2 | PWR_CR2_CWUPF1; + #elif defined(STM32H7) + // TODO #else // clear global wake-up flag PWR->CR |= PWR_CR_CWUF; From 2858e0aef8d3c1504c84b28e80c5a9e15f11cbac Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 23 Feb 2018 19:47:27 +0200 Subject: [PATCH 422/828] stm32/usbd_conf: Add USB support for H7 MCUs. --- ports/stm32/usbd_conf.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index e8031c49b3..abc12958e0 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -69,7 +69,11 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + #if defined(STM32H7) + GPIO_InitStruct.Alternate = GPIO_AF10_OTG1_FS; + #else GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS; + #endif HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* Configure VBUS Pin */ @@ -86,10 +90,15 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) GPIO_InitStruct.Pin = GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); #endif + #if defined(STM32H7) + // Keep USB clock running during sleep or else __WFI() will disable the USB + __HAL_RCC_USB2_OTG_FS_CLK_SLEEP_ENABLE(); + __HAL_RCC_USB2_OTG_FS_ULPI_CLK_SLEEP_DISABLE(); + #endif + /* Enable USB FS Clocks */ __USB_OTG_FS_CLK_ENABLE(); From fe29419c10acde8c9a09a8b3a9e9b1d1a1fa8e66 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 23 Feb 2018 19:48:30 +0200 Subject: [PATCH 423/828] stm32/stm32_it: Add support for H7 MCUs. --- ports/stm32/stm32_it.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index f933250b1f..0ad71771cb 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -385,8 +385,13 @@ STATIC void OTG_CMD_WKUP_Handler(PCD_HandleTypeDef *pcd_handle) { /* Select PLL as SYSCLK */ MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_SYSCLKSOURCE_PLLCLK); + #if defined(STM32H7) + while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL1) + {} + #else while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL) {} + #endif /* ungate PHY clock */ __HAL_PCD_UNGATE_PHYCLOCK(pcd_handle); From 0e51e4d13986e7dc65eb6186253cc1812d966647 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 23 Feb 2018 20:18:52 +0200 Subject: [PATCH 424/828] stm32/dma: Add DMA support for H7 MCUs. --- ports/stm32/dma.c | 82 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index f43daaab06..5192efa875 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -53,7 +53,7 @@ typedef enum { } dma_id_t; typedef struct _dma_descr_t { - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) || defined(STM32H7) DMA_Stream_TypeDef *instance; #elif defined(MCU_SERIES_L4) DMA_Channel_TypeDef *instance; @@ -308,6 +308,82 @@ static const uint8_t dma_irqn[NSTREAM] = { DMA2_Channel7_IRQn, }; +#elif defined(STM32H7) + +#define NCONTROLLERS (2) +#define NSTREAMS_PER_CONTROLLER (8) +#define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER) + +#define DMA_SUB_INSTANCE_AS_UINT8(dma_channel) (dma_channel) + +#define DMA1_ENABLE_MASK (0x00ff) // Bits in dma_enable_mask corresponding to DMA1 +#define DMA2_ENABLE_MASK (0xff00) // Bits in dma_enable_mask corresponding to DMA2 + +// These descriptors are ordered by DMAx_Stream number, and within a stream by channel +// number. The duplicate streams are ok as long as they aren't used at the same time. +// +// Currently I2C and SPI are synchronous and they call dma_init/dma_deinit +// around each transfer. + +// DMA1 streams +const dma_descr_t dma_I2C_1_RX = { DMA1_Stream0, DMA_REQUEST_I2C1_RX, DMA_PERIPH_TO_MEMORY, dma_id_0, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_3_RX = { DMA1_Stream2, DMA_REQUEST_SPI3_RX, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_4_RX = { DMA1_Stream2, BDMA_REQUEST_I2C4_RX, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_3_RX = { DMA1_Stream2, DMA_REQUEST_I2C3_RX, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_2_RX = { DMA1_Stream2, DMA_REQUEST_I2C2_RX, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_2_RX = { DMA1_Stream3, DMA_REQUEST_SPI2_RX, DMA_PERIPH_TO_MEMORY, dma_id_3, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_2_TX = { DMA1_Stream4, DMA_REQUEST_SPI2_TX, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_3_TX = { DMA1_Stream4, DMA_REQUEST_I2C3_TX, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_4_TX = { DMA1_Stream5, BDMA_REQUEST_I2C4_TX, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_spi_i2c }; +#if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC +const dma_descr_t dma_DAC_1_TX = { DMA1_Stream5, DMA_REQUEST_DAC1_TX, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_dac }; +const dma_descr_t dma_DAC_2_TX = { DMA1_Stream6, DMA_REQUEST_DAC2_TX, DMA_MEMORY_TO_PERIPH, dma_id_6, &dma_init_struct_dac }; +#endif +const dma_descr_t dma_SPI_3_TX = { DMA1_Stream7, DMA_REQUEST_SPI3_TX, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_1_TX = { DMA1_Stream7, DMA_REQUEST_I2C1_TX, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_2_TX = { DMA1_Stream7, DMA_REQUEST_I2C2_TX, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c }; + +// DMA2 streams +#if defined(SDMMC2) && MICROPY_HW_HAS_SDCARD +const dma_descr_t dma_SDMMC_2_RX= { DMA2_Stream0, DMA_CHANNEL_11, DMA_PERIPH_TO_MEMORY, dma_id_8, &dma_init_struct_sdio }; +#endif +const dma_descr_t dma_SPI_1_RX = { DMA2_Stream2, DMA_REQUEST_SPI1_RX, DMA_PERIPH_TO_MEMORY, dma_id_10, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_5_RX = { DMA2_Stream3, DMA_REQUEST_SPI5_RX, DMA_PERIPH_TO_MEMORY, dma_id_11, &dma_init_struct_spi_i2c }; +#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD +const dma_descr_t dma_SDIO_0_RX= { DMA2_Stream3, DMA_CHANNEL_4, DMA_PERIPH_TO_MEMORY, dma_id_11, &dma_init_struct_sdio }; +#endif +const dma_descr_t dma_SPI_4_RX = { DMA2_Stream3, DMA_REQUEST_SPI4_RX, DMA_PERIPH_TO_MEMORY, dma_id_11, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_5_TX = { DMA2_Stream4, DMA_REQUEST_SPI5_TX, DMA_MEMORY_TO_PERIPH, dma_id_12, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_4_TX = { DMA2_Stream4, DMA_REQUEST_SPI4_TX, DMA_MEMORY_TO_PERIPH, dma_id_12, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_6_TX = { DMA2_Stream5, BDMA_REQUEST_SPI6_TX, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_1_TX = { DMA2_Stream5, DMA_REQUEST_SPI1_TX, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_spi_i2c }; +#if defined(SDMMC2) && MICROPY_HW_HAS_SDCARD +const dma_descr_t dma_SDMMC_2_TX= { DMA2_Stream5, DMA_CHANNEL_11, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_sdio }; +#endif +const dma_descr_t dma_SPI_6_RX = { DMA2_Stream6, BDMA_REQUEST_SPI6_RX, DMA_PERIPH_TO_MEMORY, dma_id_14, &dma_init_struct_spi_i2c }; +#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD +const dma_descr_t dma_SDIO_0_TX= { DMA2_Stream6, DMA_CHANNEL_4, DMA_MEMORY_TO_PERIPH, dma_id_14, &dma_init_struct_sdio }; +#endif + +static const uint8_t dma_irqn[NSTREAM] = { + DMA1_Stream0_IRQn, + DMA1_Stream1_IRQn, + DMA1_Stream2_IRQn, + DMA1_Stream3_IRQn, + DMA1_Stream4_IRQn, + DMA1_Stream5_IRQn, + DMA1_Stream6_IRQn, + DMA1_Stream7_IRQn, + DMA2_Stream0_IRQn, + DMA2_Stream1_IRQn, + DMA2_Stream2_IRQn, + DMA2_Stream3_IRQn, + DMA2_Stream4_IRQn, + DMA2_Stream5_IRQn, + DMA2_Stream6_IRQn, + DMA2_Stream7_IRQn, +}; + #endif static DMA_HandleTypeDef *dma_handle[NSTREAM] = {NULL}; @@ -320,7 +396,7 @@ volatile dma_idle_count_t dma_idle; #define DMA1_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA1EN) != 0) #define DMA2_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA2EN) != 0) -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) || defined(STM32H7) void DMA1_Stream0_IRQHandler(void) { IRQ_ENTER(DMA1_Stream0_IRQn); if (dma_handle[dma_id_0] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_0]); } IRQ_EXIT(DMA1_Stream0_IRQn); } void DMA1_Stream1_IRQHandler(void) { IRQ_ENTER(DMA1_Stream1_IRQn); if (dma_handle[dma_id_1] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_1]); } IRQ_EXIT(DMA1_Stream1_IRQn); } @@ -409,7 +485,7 @@ void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void dma->Instance = dma_descr->instance; dma->Init = *dma_descr->init; dma->Init.Direction = dma_descr->transfer_direction; - #if defined(MCU_SERIES_L4) + #if defined(MCU_SERIES_L4) || defined(STM32H7) dma->Init.Request = dma_descr->sub_instance; #else dma->Init.Channel = dma_descr->sub_instance; From 711f817c2a6e9ac0321c93b44042d32482e7fdf3 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Sat, 24 Feb 2018 01:11:25 +0200 Subject: [PATCH 425/828] stm32/rtc: Add RTC support for H7 MCUs. --- ports/stm32/rtc.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index c0bc0f5b64..7e67b7c622 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -223,12 +223,16 @@ STATIC HAL_StatusTypeDef PYB_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruc /*------------------------------ LSE Configuration -------------------------*/ if ((RCC_OscInitStruct->OscillatorType & RCC_OSCILLATORTYPE_LSE) == RCC_OSCILLATORTYPE_LSE) { + #if !defined(STM32H7) // Enable Power Clock __HAL_RCC_PWR_CLK_ENABLE(); + #endif + + // Enable access to the backup domain HAL_PWR_EnableBkUpAccess(); uint32_t tickstart = HAL_GetTick(); - #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) + #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) || defined(STM32H7) //__HAL_RCC_PWR_CLK_ENABLE(); // Enable write access to Backup domain //PWR->CR1 |= PWR_CR1_DBP; @@ -298,7 +302,7 @@ STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc) { // Exit Initialization mode hrtc->Instance->ISR &= (uint32_t)~RTC_ISR_INIT; - #if defined(MCU_SERIES_L4) + #if defined(MCU_SERIES_L4) || defined(STM32H7) hrtc->Instance->OR &= (uint32_t)~RTC_OR_ALARMOUTTYPE; hrtc->Instance->OR |= (uint32_t)(hrtc->Init.OutPutType); #elif defined(MCU_SERIES_F7) @@ -634,6 +638,9 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) { #if defined(MCU_SERIES_L4) EXTI->IMR1 |= 1 << 22; EXTI->RTSR1 |= 1 << 22; + #elif defined(STM32H7) + EXTI_D1->IMR1 |= 1 << 22; + EXTI->RTSR1 |= 1 << 22; #else EXTI->IMR |= 1 << 22; EXTI->RTSR |= 1 << 22; @@ -643,6 +650,8 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) { RTC->ISR &= ~(1 << 10); #if defined(MCU_SERIES_L4) EXTI->PR1 = 1 << 22; + #elif defined(STM32H7) + EXTI_D1->PR1 = 1 << 22; #else EXTI->PR = 1 << 22; #endif @@ -661,6 +670,8 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) { // disable external interrupts on line 22 #if defined(MCU_SERIES_L4) EXTI->IMR1 &= ~(1 << 22); + #elif defined(STM32H7) + EXTI_D1->IMR1 |= 1 << 22; #else EXTI->IMR &= ~(1 << 22); #endif From 6d3f42f7139b702660ea41ef3994c05323e70307 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Sat, 24 Feb 2018 01:11:50 +0200 Subject: [PATCH 426/828] stm32/extint: Add EXTI support for H7 MCUs. --- ports/stm32/extint.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c index 423af2ac36..be4d20bb4d 100644 --- a/ports/stm32/extint.c +++ b/ports/stm32/extint.c @@ -97,6 +97,11 @@ #define EXTI_Mode_Event offsetof(EXTI_TypeDef, EMR1) #define EXTI_RTSR EXTI->RTSR1 #define EXTI_FTSR EXTI->FTSR1 +#elif defined(STM32H7) +#define EXTI_Mode_Interrupt offsetof(EXTI_Core_TypeDef, IMR1) +#define EXTI_Mode_Event offsetof(EXTI_Core_TypeDef, EMR1) +#define EXTI_RTSR EXTI->RTSR1 +#define EXTI_FTSR EXTI->FTSR1 #else #define EXTI_Mode_Interrupt offsetof(EXTI_TypeDef, IMR) #define EXTI_Mode_Event offsetof(EXTI_TypeDef, EMR) @@ -277,13 +282,21 @@ void extint_enable(uint line) { if (line >= EXTI_NUM_VECTORS) { return; } - #if defined(MCU_SERIES_F7) + #if defined(MCU_SERIES_F7) || defined(STM32H7) // The Cortex-M7 doesn't have bitband support. mp_uint_t irq_state = disable_irq(); if (pyb_extint_mode[line] == EXTI_Mode_Interrupt) { + #if defined(STM32H7) + EXTI_D1->IMR1 |= (1 << line); + #else EXTI->IMR |= (1 << line); + #endif } else { + #if defined(STM32H7) + EXTI_D1->EMR1 |= (1 << line); + #else EXTI->EMR |= (1 << line); + #endif } enable_irq(irq_state); #else @@ -299,11 +312,16 @@ void extint_disable(uint line) { return; } - #if defined(MCU_SERIES_F7) + #if defined(MCU_SERIES_F7) || defined(STM32H7) // The Cortex-M7 doesn't have bitband support. mp_uint_t irq_state = disable_irq(); + #if defined(STM32H7) + EXTI_D1->IMR1 &= ~(1 << line); + EXTI_D1->EMR1 &= ~(1 << line); + #else EXTI->IMR &= ~(1 << line); EXTI->EMR &= ~(1 << line); + #endif enable_irq(irq_state); #else // Since manipulating IMR/EMR is a read-modify-write, and we want this to @@ -319,7 +337,7 @@ void extint_swint(uint line) { return; } // we need 0 to 1 transition to trigger the interrupt -#if defined(MCU_SERIES_L4) +#if defined(MCU_SERIES_L4) || defined(STM32H7) EXTI->SWIER1 &= ~(1 << line); EXTI->SWIER1 |= (1 << line); #else @@ -381,6 +399,25 @@ STATIC mp_obj_t extint_regs(void) { printf("EXTI_SWIER2 %08lx\n", EXTI->SWIER2); printf("EXTI_PR1 %08lx\n", EXTI->PR1); printf("EXTI_PR2 %08lx\n", EXTI->PR2); + #elif defined(STM32H7) + printf("EXTI_IMR1 %08lx\n", EXTI_D1->IMR1); + printf("EXTI_IMR2 %08lx\n", EXTI_D1->IMR2); + printf("EXTI_IMR3 %08lx\n", EXTI_D1->IMR3); + printf("EXTI_EMR1 %08lx\n", EXTI_D1->EMR1); + printf("EXTI_EMR2 %08lx\n", EXTI_D1->EMR2); + printf("EXTI_EMR3 %08lx\n", EXTI_D1->EMR3); + printf("EXTI_RTSR1 %08lx\n", EXTI->RTSR1); + printf("EXTI_RTSR2 %08lx\n", EXTI->RTSR2); + printf("EXTI_RTSR3 %08lx\n", EXTI->RTSR3); + printf("EXTI_FTSR1 %08lx\n", EXTI->FTSR1); + printf("EXTI_FTSR2 %08lx\n", EXTI->FTSR2); + printf("EXTI_FTSR3 %08lx\n", EXTI->FTSR3); + printf("EXTI_SWIER1 %08lx\n", EXTI->SWIER1); + printf("EXTI_SWIER2 %08lx\n", EXTI->SWIER2); + printf("EXTI_SWIER3 %08lx\n", EXTI->SWIER3); + printf("EXTI_PR1 %08lx\n", EXTI_D1->PR1); + printf("EXTI_PR2 %08lx\n", EXTI_D1->PR2); + printf("EXTI_PR3 %08lx\n", EXTI_D1->PR3); #else printf("EXTI_IMR %08lx\n", EXTI->IMR); printf("EXTI_EMR %08lx\n", EXTI->EMR); From 61d463ad072822f4f0104b4ab46fda5173ebc2f6 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Sun, 25 Feb 2018 02:00:12 +0200 Subject: [PATCH 427/828] stm32/mpconfigboard_common: Add STM32H7 common configuration. --- ports/stm32/mpconfigboard_common.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 7befe998af..0c57976fb9 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -116,6 +116,14 @@ #define MICROPY_HW_MAX_TIMER (17) #define MICROPY_HW_MAX_UART (8) +// Configuration for STM32H7 series +#elif defined(STM32H7) + +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff1e800) +#define PYB_EXTI_NUM_VECTORS (24) +#define MICROPY_HW_MAX_TIMER (17) +#define MICROPY_HW_MAX_UART (8) + // Configuration for STM32L4 series #elif defined(STM32L4) From bbf19bb64e1ad62b3c2852c4a24d09fbcac5c9c6 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 2 Mar 2018 17:07:25 +0200 Subject: [PATCH 428/828] stm32/main: Enable D2 SRAM1/2/3 clocks on H7 MCUs. --- ports/stm32/main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index cb3bdf7496..5fd2787e09 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -442,8 +442,14 @@ int main(void) { // enable the CCM RAM __HAL_RCC_CCMDATARAMEN_CLK_ENABLE(); #endif + #elif defined(STM32H7) + // Enable D2 SRAM1/2/3 clocks. + __HAL_RCC_D2SRAM1_CLK_ENABLE(); + __HAL_RCC_D2SRAM2_CLK_ENABLE(); + __HAL_RCC_D2SRAM3_CLK_ENABLE(); #endif + #if defined(MICROPY_BOARD_EARLY_INIT) MICROPY_BOARD_EARLY_INIT(); #endif From 0f5cce7753703f8e7bb3f5a28c5b3f5bb46915c2 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Mon, 5 Mar 2018 16:31:23 +0200 Subject: [PATCH 429/828] stm32/boards: Add startup_stm32h7.s for H7 series specific startup. --- ports/stm32/boards/startup_stm32h7.s | 763 +++++++++++++++++++++++++++ 1 file changed, 763 insertions(+) create mode 100644 ports/stm32/boards/startup_stm32h7.s diff --git a/ports/stm32/boards/startup_stm32h7.s b/ports/stm32/boards/startup_stm32h7.s new file mode 100644 index 0000000000..53d46205fd --- /dev/null +++ b/ports/stm32/boards/startup_stm32h7.s @@ -0,0 +1,763 @@ +/** + ****************************************************************************** + * @file startup_stm32h743xx.s + * @author MCD Application Team + * @version V1.2.0 + * @date 29-December-2017 + * @brief STM32H743xx Devices vector table for GCC based toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m7 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss +/* stack used for SystemInit_ExtMemCtl; always internal RAM used */ + +/** + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval : None +*/ + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr sp, =_estack /* set stack pointer */ + +/* Copy the data segment initializers from flash to SRAM */ + movs r1, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r3, =_sidata + ldr r3, [r3, r1] + str r3, [r0, r1] + adds r1, r1, #4 + +LoopCopyDataInit: + ldr r0, =_sdata + ldr r3, =_edata + adds r2, r0, r1 + cmp r2, r3 + bcc CopyDataInit + ldr r2, =_sbss + b LoopFillZerobss +/* Zero fill the bss segment. */ +FillZerobss: + movs r3, #0 + str r3, [r2], #4 + +LoopFillZerobss: + ldr r3, = _ebss + cmp r2, r3 + bcc FillZerobss + +/* Call the clock system intitialization function.*/ + bl SystemInit +/* Call static constructors */ +/* bl __libc_init_array */ +/* Call the application's entry point.*/ + bl main + bx lr +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * @param None + * @retval None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex M. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +*******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + .word _estack + .word Reset_Handler + + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + + /* External Interrupts */ + .word WWDG_IRQHandler /* Window WatchDog */ + .word PVD_AVD_IRQHandler /* PVD/AVD through EXTI Line detection */ + .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ + .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ + .word FLASH_IRQHandler /* FLASH */ + .word RCC_IRQHandler /* RCC */ + .word EXTI0_IRQHandler /* EXTI Line0 */ + .word EXTI1_IRQHandler /* EXTI Line1 */ + .word EXTI2_IRQHandler /* EXTI Line2 */ + .word EXTI3_IRQHandler /* EXTI Line3 */ + .word EXTI4_IRQHandler /* EXTI Line4 */ + .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */ + .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */ + .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */ + .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */ + .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */ + .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */ + .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */ + .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */ + .word FDCAN1_IT0_IRQHandler /* FDCAN1 interrupt line 0 */ + .word FDCAN2_IT0_IRQHandler /* FDCAN2 interrupt line 0 */ + .word FDCAN1_IT1_IRQHandler /* FDCAN1 interrupt line 1 */ + .word FDCAN2_IT1_IRQHandler /* FDCAN2 interrupt line 1 */ + .word EXTI9_5_IRQHandler /* External Line[9:5]s */ + .word TIM1_BRK_IRQHandler /* TIM1 Break interrupt */ + .word TIM1_UP_IRQHandler /* TIM1 Update interrupt */ + .word TIM1_TRG_COM_IRQHandler /* TIM1 Trigger and Commutation interrupt */ + .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ + .word TIM2_IRQHandler /* TIM2 */ + .word TIM3_IRQHandler /* TIM3 */ + .word TIM4_IRQHandler /* TIM4 */ + .word I2C1_EV_IRQHandler /* I2C1 Event */ + .word I2C1_ER_IRQHandler /* I2C1 Error */ + .word I2C2_EV_IRQHandler /* I2C2 Event */ + .word I2C2_ER_IRQHandler /* I2C2 Error */ + .word SPI1_IRQHandler /* SPI1 */ + .word SPI2_IRQHandler /* SPI2 */ + .word USART1_IRQHandler /* USART1 */ + .word USART2_IRQHandler /* USART2 */ + .word USART3_IRQHandler /* USART3 */ + .word EXTI15_10_IRQHandler /* External Line[15:10]s */ + .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ + .word 0 /* Reserved */ + .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */ + .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */ + .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */ + .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ + .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */ + .word FMC_IRQHandler /* FMC */ + .word SDMMC1_IRQHandler /* SDMMC1 */ + .word TIM5_IRQHandler /* TIM5 */ + .word SPI3_IRQHandler /* SPI3 */ + .word UART4_IRQHandler /* UART4 */ + .word UART5_IRQHandler /* UART5 */ + .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */ + .word TIM7_IRQHandler /* TIM7 */ + .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */ + .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */ + .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */ + .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */ + .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */ + .word ETH_IRQHandler /* Ethernet */ + .word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */ + .word FDCAN_CAL_IRQHandler /* FDCAN calibration unit interrupt*/ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */ + .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */ + .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */ + .word USART6_IRQHandler /* USART6 */ + .word I2C3_EV_IRQHandler /* I2C3 event */ + .word I2C3_ER_IRQHandler /* I2C3 error */ + .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */ + .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */ + .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */ + .word OTG_HS_IRQHandler /* USB OTG HS */ + .word DCMI_IRQHandler /* DCMI */ + .word 0 /* Reserved */ + .word RNG_IRQHandler /* Rng */ + .word FPU_IRQHandler /* FPU */ + .word UART7_IRQHandler /* UART7 */ + .word UART8_IRQHandler /* UART8 */ + .word SPI4_IRQHandler /* SPI4 */ + .word SPI5_IRQHandler /* SPI5 */ + .word SPI6_IRQHandler /* SPI6 */ + .word SAI1_IRQHandler /* SAI1 */ + .word LTDC_IRQHandler /* LTDC */ + .word LTDC_ER_IRQHandler /* LTDC error */ + .word DMA2D_IRQHandler /* DMA2D */ + .word SAI2_IRQHandler /* SAI2 */ + .word QUADSPI_IRQHandler /* QUADSPI */ + .word LPTIM1_IRQHandler /* LPTIM1 */ + .word CEC_IRQHandler /* HDMI_CEC */ + .word I2C4_EV_IRQHandler /* I2C4 Event */ + .word I2C4_ER_IRQHandler /* I2C4 Error */ + .word SPDIF_RX_IRQHandler /* SPDIF_RX */ + .word OTG_FS_EP1_OUT_IRQHandler /* USB OTG FS End Point 1 Out */ + .word OTG_FS_EP1_IN_IRQHandler /* USB OTG FS End Point 1 In */ + .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI */ + .word OTG_FS_IRQHandler /* USB OTG FS */ + .word DMAMUX1_OVR_IRQHandler /* DMAMUX1 Overrun interrupt */ + .word HRTIM1_Master_IRQHandler /* HRTIM Master Timer global Interrupt */ + .word HRTIM1_TIMA_IRQHandler /* HRTIM Timer A global Interrupt */ + .word HRTIM1_TIMB_IRQHandler /* HRTIM Timer B global Interrupt */ + .word HRTIM1_TIMC_IRQHandler /* HRTIM Timer C global Interrupt */ + .word HRTIM1_TIMD_IRQHandler /* HRTIM Timer D global Interrupt */ + .word HRTIM1_TIME_IRQHandler /* HRTIM Timer E global Interrupt */ + .word HRTIM1_FLT_IRQHandler /* HRTIM Fault global Interrupt */ + .word DFSDM1_FLT0_IRQHandler /* DFSDM Filter0 Interrupt */ + .word DFSDM1_FLT1_IRQHandler /* DFSDM Filter1 Interrupt */ + .word DFSDM1_FLT2_IRQHandler /* DFSDM Filter2 Interrupt */ + .word DFSDM1_FLT3_IRQHandler /* DFSDM Filter3 Interrupt */ + .word SAI3_IRQHandler /* SAI3 global Interrupt */ + .word SWPMI1_IRQHandler /* Serial Wire Interface 1 global interrupt */ + .word TIM15_IRQHandler /* TIM15 global Interrupt */ + .word TIM16_IRQHandler /* TIM16 global Interrupt */ + .word TIM17_IRQHandler /* TIM17 global Interrupt */ + .word MDIOS_WKUP_IRQHandler /* MDIOS Wakeup Interrupt */ + .word MDIOS_IRQHandler /* MDIOS global Interrupt */ + .word JPEG_IRQHandler /* JPEG global Interrupt */ + .word MDMA_IRQHandler /* MDMA global Interrupt */ + .word 0 /* Reserved */ + .word SDMMC2_IRQHandler /* SDMMC2 global Interrupt */ + .word HSEM1_IRQHandler /* HSEM1 global Interrupt */ + .word 0 /* Reserved */ + .word ADC3_IRQHandler /* ADC3 global Interrupt */ + .word DMAMUX2_OVR_IRQHandler /* DMAMUX Overrun interrupt */ + .word BDMA_Channel0_IRQHandler /* BDMA Channel 0 global Interrupt */ + .word BDMA_Channel1_IRQHandler /* BDMA Channel 1 global Interrupt */ + .word BDMA_Channel2_IRQHandler /* BDMA Channel 2 global Interrupt */ + .word BDMA_Channel3_IRQHandler /* BDMA Channel 3 global Interrupt */ + .word BDMA_Channel4_IRQHandler /* BDMA Channel 4 global Interrupt */ + .word BDMA_Channel5_IRQHandler /* BDMA Channel 5 global Interrupt */ + .word BDMA_Channel6_IRQHandler /* BDMA Channel 6 global Interrupt */ + .word BDMA_Channel7_IRQHandler /* BDMA Channel 7 global Interrupt */ + .word COMP1_IRQHandler /* COMP1 global Interrupt */ + .word LPTIM2_IRQHandler /* LP TIM2 global interrupt */ + .word LPTIM3_IRQHandler /* LP TIM3 global interrupt */ + .word LPTIM4_IRQHandler /* LP TIM4 global interrupt */ + .word LPTIM5_IRQHandler /* LP TIM5 global interrupt */ + .word LPUART1_IRQHandler /* LP UART1 interrupt */ + .word 0 /* Reserved */ + .word CRS_IRQHandler /* Clock Recovery Global Interrupt */ + .word 0 /* Reserved */ + .word SAI4_IRQHandler /* SAI4 global interrupt */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word WAKEUP_PIN_IRQHandler /* Interrupt for all 6 wake-up pins */ + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_AVD_IRQHandler + .thumb_set PVD_AVD_IRQHandler,Default_Handler + + .weak TAMP_STAMP_IRQHandler + .thumb_set TAMP_STAMP_IRQHandler,Default_Handler + + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + + .weak DMA1_Stream0_IRQHandler + .thumb_set DMA1_Stream0_IRQHandler,Default_Handler + + .weak DMA1_Stream1_IRQHandler + .thumb_set DMA1_Stream1_IRQHandler,Default_Handler + + .weak DMA1_Stream2_IRQHandler + .thumb_set DMA1_Stream2_IRQHandler,Default_Handler + + .weak DMA1_Stream3_IRQHandler + .thumb_set DMA1_Stream3_IRQHandler,Default_Handler + + .weak DMA1_Stream4_IRQHandler + .thumb_set DMA1_Stream4_IRQHandler,Default_Handler + + .weak DMA1_Stream5_IRQHandler + .thumb_set DMA1_Stream5_IRQHandler,Default_Handler + + .weak DMA1_Stream6_IRQHandler + .thumb_set DMA1_Stream6_IRQHandler,Default_Handler + + .weak ADC_IRQHandler + .thumb_set ADC_IRQHandler,Default_Handler + + .weak FDCAN1_IT0_IRQHandler + .thumb_set FDCAN1_IT0_IRQHandler,Default_Handler + + .weak FDCAN2_IT0_IRQHandler + .thumb_set FDCAN2_IT0_IRQHandler,Default_Handler + + .weak FDCAN1_IT1_IRQHandler + .thumb_set FDCAN1_IT1_IRQHandler,Default_Handler + + .weak FDCAN2_IT1_IRQHandler + .thumb_set FDCAN2_IT1_IRQHandler,Default_Handler + + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + + .weak TIM1_BRK_IRQHandler + .thumb_set TIM1_BRK_IRQHandler,Default_Handler + + .weak TIM1_UP_IRQHandler + .thumb_set TIM1_UP_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_IRQHandler + .thumb_set TIM1_TRG_COM_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + + .weak TIM4_IRQHandler + .thumb_set TIM4_IRQHandler,Default_Handler + + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + + .weak I2C2_EV_IRQHandler + .thumb_set I2C2_EV_IRQHandler,Default_Handler + + .weak I2C2_ER_IRQHandler + .thumb_set I2C2_ER_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + + .weak USART3_IRQHandler + .thumb_set USART3_IRQHandler,Default_Handler + + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + + .weak TIM8_BRK_TIM12_IRQHandler + .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler + + .weak TIM8_UP_TIM13_IRQHandler + .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler + + .weak TIM8_TRG_COM_TIM14_IRQHandler + .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler + + .weak TIM8_CC_IRQHandler + .thumb_set TIM8_CC_IRQHandler,Default_Handler + + .weak DMA1_Stream7_IRQHandler + .thumb_set DMA1_Stream7_IRQHandler,Default_Handler + + .weak FMC_IRQHandler + .thumb_set FMC_IRQHandler,Default_Handler + + .weak SDMMC1_IRQHandler + .thumb_set SDMMC1_IRQHandler,Default_Handler + + .weak TIM5_IRQHandler + .thumb_set TIM5_IRQHandler,Default_Handler + + .weak SPI3_IRQHandler + .thumb_set SPI3_IRQHandler,Default_Handler + + .weak UART4_IRQHandler + .thumb_set UART4_IRQHandler,Default_Handler + + .weak UART5_IRQHandler + .thumb_set UART5_IRQHandler,Default_Handler + + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + + .weak DMA2_Stream0_IRQHandler + .thumb_set DMA2_Stream0_IRQHandler,Default_Handler + + .weak DMA2_Stream1_IRQHandler + .thumb_set DMA2_Stream1_IRQHandler,Default_Handler + + .weak DMA2_Stream2_IRQHandler + .thumb_set DMA2_Stream2_IRQHandler,Default_Handler + + .weak DMA2_Stream3_IRQHandler + .thumb_set DMA2_Stream3_IRQHandler,Default_Handler + + .weak DMA2_Stream4_IRQHandler + .thumb_set DMA2_Stream4_IRQHandler,Default_Handler + + .weak ETH_IRQHandler + .thumb_set ETH_IRQHandler,Default_Handler + + .weak ETH_WKUP_IRQHandler + .thumb_set ETH_WKUP_IRQHandler,Default_Handler + + .weak FDCAN_CAL_IRQHandler + .thumb_set FDCAN_CAL_IRQHandler,Default_Handler + + .weak DMA2_Stream5_IRQHandler + .thumb_set DMA2_Stream5_IRQHandler,Default_Handler + + .weak DMA2_Stream6_IRQHandler + .thumb_set DMA2_Stream6_IRQHandler,Default_Handler + + .weak DMA2_Stream7_IRQHandler + .thumb_set DMA2_Stream7_IRQHandler,Default_Handler + + .weak USART6_IRQHandler + .thumb_set USART6_IRQHandler,Default_Handler + + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_OUT_IRQHandler + .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_IN_IRQHandler + .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler + + .weak OTG_HS_WKUP_IRQHandler + .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler + + .weak OTG_HS_IRQHandler + .thumb_set OTG_HS_IRQHandler,Default_Handler + + .weak DCMI_IRQHandler + .thumb_set DCMI_IRQHandler,Default_Handler + + .weak RNG_IRQHandler + .thumb_set RNG_IRQHandler,Default_Handler + + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + + .weak UART7_IRQHandler + .thumb_set UART7_IRQHandler,Default_Handler + + .weak UART8_IRQHandler + .thumb_set UART8_IRQHandler,Default_Handler + + .weak SPI4_IRQHandler + .thumb_set SPI4_IRQHandler,Default_Handler + + .weak SPI5_IRQHandler + .thumb_set SPI5_IRQHandler,Default_Handler + + .weak SPI6_IRQHandler + .thumb_set SPI6_IRQHandler,Default_Handler + + .weak SAI1_IRQHandler + .thumb_set SAI1_IRQHandler,Default_Handler + + .weak LTDC_IRQHandler + .thumb_set LTDC_IRQHandler,Default_Handler + + .weak LTDC_ER_IRQHandler + .thumb_set LTDC_ER_IRQHandler,Default_Handler + + .weak DMA2D_IRQHandler + .thumb_set DMA2D_IRQHandler,Default_Handler + + .weak SAI2_IRQHandler + .thumb_set SAI2_IRQHandler,Default_Handler + + .weak QUADSPI_IRQHandler + .thumb_set QUADSPI_IRQHandler,Default_Handler + + .weak LPTIM1_IRQHandler + .thumb_set LPTIM1_IRQHandler,Default_Handler + + .weak CEC_IRQHandler + .thumb_set CEC_IRQHandler,Default_Handler + + .weak I2C4_EV_IRQHandler + .thumb_set I2C4_EV_IRQHandler,Default_Handler + + .weak I2C4_ER_IRQHandler + .thumb_set I2C4_ER_IRQHandler,Default_Handler + + .weak SPDIF_RX_IRQHandler + .thumb_set SPDIF_RX_IRQHandler,Default_Handler + + .weak OTG_FS_EP1_OUT_IRQHandler + .thumb_set OTG_FS_EP1_OUT_IRQHandler,Default_Handler + + .weak OTG_FS_EP1_IN_IRQHandler + .thumb_set OTG_FS_EP1_IN_IRQHandler,Default_Handler + + .weak OTG_FS_WKUP_IRQHandler + .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler + + .weak OTG_FS_IRQHandler + .thumb_set OTG_FS_IRQHandler,Default_Handler + + .weak DMAMUX1_OVR_IRQHandler + .thumb_set DMAMUX1_OVR_IRQHandler,Default_Handler + + .weak HRTIM1_Master_IRQHandler + .thumb_set HRTIM1_Master_IRQHandler,Default_Handler + + .weak HRTIM1_TIMA_IRQHandler + .thumb_set HRTIM1_TIMA_IRQHandler,Default_Handler + + .weak HRTIM1_TIMB_IRQHandler + .thumb_set HRTIM1_TIMB_IRQHandler,Default_Handler + + .weak HRTIM1_TIMC_IRQHandler + .thumb_set HRTIM1_TIMC_IRQHandler,Default_Handler + + .weak HRTIM1_TIMD_IRQHandler + .thumb_set HRTIM1_TIMD_IRQHandler,Default_Handler + + .weak HRTIM1_TIME_IRQHandler + .thumb_set HRTIM1_TIME_IRQHandler,Default_Handler + + .weak HRTIM1_FLT_IRQHandler + .thumb_set HRTIM1_FLT_IRQHandler,Default_Handler + + .weak DFSDM1_FLT0_IRQHandler + .thumb_set DFSDM1_FLT0_IRQHandler,Default_Handler + + .weak DFSDM1_FLT1_IRQHandler + .thumb_set DFSDM1_FLT1_IRQHandler,Default_Handler + + .weak DFSDM1_FLT2_IRQHandler + .thumb_set DFSDM1_FLT2_IRQHandler,Default_Handler + + .weak DFSDM1_FLT3_IRQHandler + .thumb_set DFSDM1_FLT3_IRQHandler,Default_Handler + + .weak SAI3_IRQHandler + .thumb_set SAI3_IRQHandler,Default_Handler + + .weak SWPMI1_IRQHandler + .thumb_set SWPMI1_IRQHandler,Default_Handler + + .weak TIM15_IRQHandler + .thumb_set TIM15_IRQHandler,Default_Handler + + .weak TIM16_IRQHandler + .thumb_set TIM16_IRQHandler,Default_Handler + + .weak TIM17_IRQHandler + .thumb_set TIM17_IRQHandler,Default_Handler + + .weak MDIOS_WKUP_IRQHandler + .thumb_set MDIOS_WKUP_IRQHandler,Default_Handler + + .weak MDIOS_IRQHandler + .thumb_set MDIOS_IRQHandler,Default_Handler + + .weak JPEG_IRQHandler + .thumb_set JPEG_IRQHandler,Default_Handler + + .weak MDMA_IRQHandler + .thumb_set MDMA_IRQHandler,Default_Handler + + .weak SDMMC2_IRQHandler + .thumb_set SDMMC2_IRQHandler,Default_Handler + + .weak HSEM1_IRQHandler + .thumb_set HSEM1_IRQHandler,Default_Handler + + .weak ADC3_IRQHandler + .thumb_set ADC3_IRQHandler,Default_Handler + + .weak DMAMUX2_OVR_IRQHandler + .thumb_set DMAMUX2_OVR_IRQHandler,Default_Handler + + .weak BDMA_Channel0_IRQHandler + .thumb_set BDMA_Channel0_IRQHandler,Default_Handler + + .weak BDMA_Channel1_IRQHandler + .thumb_set BDMA_Channel1_IRQHandler,Default_Handler + + .weak BDMA_Channel2_IRQHandler + .thumb_set BDMA_Channel2_IRQHandler,Default_Handler + + .weak BDMA_Channel3_IRQHandler + .thumb_set BDMA_Channel3_IRQHandler,Default_Handler + + .weak BDMA_Channel4_IRQHandler + .thumb_set BDMA_Channel4_IRQHandler,Default_Handler + + .weak BDMA_Channel5_IRQHandler + .thumb_set BDMA_Channel5_IRQHandler,Default_Handler + + .weak BDMA_Channel6_IRQHandler + .thumb_set BDMA_Channel6_IRQHandler,Default_Handler + + .weak BDMA_Channel7_IRQHandler + .thumb_set BDMA_Channel7_IRQHandler,Default_Handler + + .weak COMP1_IRQHandler + .thumb_set COMP1_IRQHandler,Default_Handler + + .weak LPTIM2_IRQHandler + .thumb_set LPTIM2_IRQHandler,Default_Handler + + .weak LPTIM3_IRQHandler + .thumb_set LPTIM3_IRQHandler,Default_Handler + + .weak LPTIM4_IRQHandler + .thumb_set LPTIM4_IRQHandler,Default_Handler + + .weak LPTIM5_IRQHandler + .thumb_set LPTIM5_IRQHandler,Default_Handler + + .weak LPUART1_IRQHandler + .thumb_set LPUART1_IRQHandler,Default_Handler + + .weak CRS_IRQHandler + .thumb_set CRS_IRQHandler,Default_Handler + + .weak SAI4_IRQHandler + .thumb_set SAI4_IRQHandler,Default_Handler + + .weak WAKEUP_PIN_IRQHandler + .thumb_set WAKEUP_PIN_IRQHandler,Default_Handler + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + From d84f1a90ccc8d1a60e22be3f726ec1efa7f39ac8 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Mon, 5 Mar 2018 17:59:18 +0200 Subject: [PATCH 430/828] stm32/boards: Add startup_stm32f7.s for F7 series specific startup. --- ports/stm32/boards/startup_stm32f7.s | 604 +++++++++++++++++++++++++++ 1 file changed, 604 insertions(+) create mode 100644 ports/stm32/boards/startup_stm32f7.s diff --git a/ports/stm32/boards/startup_stm32f7.s b/ports/stm32/boards/startup_stm32f7.s new file mode 100644 index 0000000000..633ba01e93 --- /dev/null +++ b/ports/stm32/boards/startup_stm32f7.s @@ -0,0 +1,604 @@ +/** + ****************************************************************************** + * @file startup_stm32.S + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief STM32Fxxxxx Devices vector table for Atollic TrueSTUDIO toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M4/M7 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m7 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss +/* stack used for SystemInit_ExtMemCtl; always internal RAM used */ + +/** + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval : None +*/ + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr sp, =_estack /* set stack pointer */ + +/* Copy the data segment initializers from flash to SRAM */ + movs r1, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r3, =_sidata + ldr r3, [r3, r1] + str r3, [r0, r1] + adds r1, r1, #4 + +LoopCopyDataInit: + ldr r0, =_sdata + ldr r3, =_edata + adds r2, r0, r1 + cmp r2, r3 + bcc CopyDataInit + ldr r2, =_sbss + b LoopFillZerobss +/* Zero fill the bss segment. */ +FillZerobss: + movs r3, #0 + str r3, [r2], #4 + +LoopFillZerobss: + ldr r3, = _ebss + cmp r2, r3 + bcc FillZerobss + +/* Call the clock system initialization function.*/ + bl SystemInit +/* Call static constructors */ + /*bl __libc_init_array*/ +/* Call the application's entry point.*/ + bl main + bx lr +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * @param None + * @retval None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex M4/M7. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +*******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + + /* External Interrupts */ + .word WWDG_IRQHandler /* Window WatchDog */ + .word PVD_IRQHandler /* PVD through EXTI Line detection */ + .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ + .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ + .word FLASH_IRQHandler /* FLASH */ + .word RCC_IRQHandler /* RCC */ + .word EXTI0_IRQHandler /* EXTI Line0 */ + .word EXTI1_IRQHandler /* EXTI Line1 */ + .word EXTI2_IRQHandler /* EXTI Line2 */ + .word EXTI3_IRQHandler /* EXTI Line3 */ + .word EXTI4_IRQHandler /* EXTI Line4 */ + .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */ + .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */ + .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */ + .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */ + .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */ + .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */ + .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */ + .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */ + .word CAN1_TX_IRQHandler /* CAN1 TX */ + .word CAN1_RX0_IRQHandler /* CAN1 RX0 */ + .word CAN1_RX1_IRQHandler /* CAN1 RX1 */ + .word CAN1_SCE_IRQHandler /* CAN1 SCE */ + .word EXTI9_5_IRQHandler /* External Line[9:5]s */ + .word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */ + .word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */ + .word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */ + .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ + .word TIM2_IRQHandler /* TIM2 */ + .word TIM3_IRQHandler /* TIM3 */ + .word TIM4_IRQHandler /* TIM4 */ + .word I2C1_EV_IRQHandler /* I2C1 Event */ + .word I2C1_ER_IRQHandler /* I2C1 Error */ + .word I2C2_EV_IRQHandler /* I2C2 Event */ + .word I2C2_ER_IRQHandler /* I2C2 Error */ + .word SPI1_IRQHandler /* SPI1 */ + .word SPI2_IRQHandler /* SPI2 */ + .word USART1_IRQHandler /* USART1 */ + .word USART2_IRQHandler /* USART2 */ + .word USART3_IRQHandler /* USART3 */ + .word EXTI15_10_IRQHandler /* External Line[15:10]s */ + .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ + .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */ + .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */ + .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */ + .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */ + .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ + .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */ + .word FMC_IRQHandler /* FMC */ + .word SDMMC1_IRQHandler /* SDMMC1 */ + .word TIM5_IRQHandler /* TIM5 */ + .word SPI3_IRQHandler /* SPI3 */ + .word UART4_IRQHandler /* UART4 */ + .word UART5_IRQHandler /* UART5 */ + .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */ + .word TIM7_IRQHandler /* TIM7 */ + .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */ + .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */ + .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */ + .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */ + .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */ + .word ETH_IRQHandler /* Ethernet */ + .word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */ + .word CAN2_TX_IRQHandler /* CAN2 TX */ + .word CAN2_RX0_IRQHandler /* CAN2 RX0 */ + .word CAN2_RX1_IRQHandler /* CAN2 RX1 */ + .word CAN2_SCE_IRQHandler /* CAN2 SCE */ + .word OTG_FS_IRQHandler /* USB OTG FS */ + .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */ + .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */ + .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */ + .word USART6_IRQHandler /* USART6 */ + .word I2C3_EV_IRQHandler /* I2C3 event */ + .word I2C3_ER_IRQHandler /* I2C3 error */ + .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */ + .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */ + .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */ + .word OTG_HS_IRQHandler /* USB OTG HS */ + .word DCMI_IRQHandler /* DCMI */ + .word 0 /* CRYP crypto */ + .word HASH_RNG_IRQHandler /* Hash and Rng */ + .word FPU_IRQHandler /* FPU */ + .word UART7_IRQHandler /* UART7 */ + .word UART8_IRQHandler /* UART8 */ + .word SPI4_IRQHandler /* SPI4 */ + .word SPI5_IRQHandler /* SPI5 */ + .word SPI6_IRQHandler /* SPI6 */ + .word SAI1_IRQHandler /* SAI1 */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word DMA2D_IRQHandler /* DMA2D */ + .word SAI2_IRQHandler /* SAI2 */ + .word QUADSPI_IRQHandler /* QUADSPI */ + .word LPTIM1_IRQHandler /* LPTIM1 */ + .word CEC_IRQHandler /* HDMI_CEC */ + .word I2C4_EV_IRQHandler /* I2C4 Event */ + .word I2C4_ER_IRQHandler /* I2C4 Error */ + .word SPDIF_RX_IRQHandler /* SPDIF_RX */ + .word DSIHOST_IRQHandler /* DSI host */ + .word DFSDM1_FLT0_IRQHandler /* DFSDM1 filter 0 */ + .word DFSDM1_FLT1_IRQHandler /* DFSDM1 filter 1 */ + .word DFSDM1_FLT2_IRQHandler /* DFSDM1 filter 2 */ + .word DFSDM1_FLT3_IRQHandler /* DFSDM1 filter 3 */ + .word SDMMC2_IRQHandler /* SDMMC2 */ + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_IRQHandler + .thumb_set PVD_IRQHandler,Default_Handler + + .weak TAMP_STAMP_IRQHandler + .thumb_set TAMP_STAMP_IRQHandler,Default_Handler + + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + + .weak DMA1_Stream0_IRQHandler + .thumb_set DMA1_Stream0_IRQHandler,Default_Handler + + .weak DMA1_Stream1_IRQHandler + .thumb_set DMA1_Stream1_IRQHandler,Default_Handler + + .weak DMA1_Stream2_IRQHandler + .thumb_set DMA1_Stream2_IRQHandler,Default_Handler + + .weak DMA1_Stream3_IRQHandler + .thumb_set DMA1_Stream3_IRQHandler,Default_Handler + + .weak DMA1_Stream4_IRQHandler + .thumb_set DMA1_Stream4_IRQHandler,Default_Handler + + .weak DMA1_Stream5_IRQHandler + .thumb_set DMA1_Stream5_IRQHandler,Default_Handler + + .weak DMA1_Stream6_IRQHandler + .thumb_set DMA1_Stream6_IRQHandler,Default_Handler + + .weak ADC_IRQHandler + .thumb_set ADC_IRQHandler,Default_Handler + + .weak CAN1_TX_IRQHandler + .thumb_set CAN1_TX_IRQHandler,Default_Handler + + .weak CAN1_RX0_IRQHandler + .thumb_set CAN1_RX0_IRQHandler,Default_Handler + + .weak CAN1_RX1_IRQHandler + .thumb_set CAN1_RX1_IRQHandler,Default_Handler + + .weak CAN1_SCE_IRQHandler + .thumb_set CAN1_SCE_IRQHandler,Default_Handler + + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + + .weak TIM1_BRK_TIM9_IRQHandler + .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler + + .weak TIM1_UP_TIM10_IRQHandler + .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_TIM11_IRQHandler + .thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + + .weak TIM4_IRQHandler + .thumb_set TIM4_IRQHandler,Default_Handler + + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + + .weak I2C2_EV_IRQHandler + .thumb_set I2C2_EV_IRQHandler,Default_Handler + + .weak I2C2_ER_IRQHandler + .thumb_set I2C2_ER_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + + .weak USART3_IRQHandler + .thumb_set USART3_IRQHandler,Default_Handler + + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + + .weak OTG_FS_WKUP_IRQHandler + .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler + + .weak TIM8_BRK_TIM12_IRQHandler + .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler + + .weak TIM8_UP_TIM13_IRQHandler + .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler + + .weak TIM8_TRG_COM_TIM14_IRQHandler + .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler + + .weak TIM8_CC_IRQHandler + .thumb_set TIM8_CC_IRQHandler,Default_Handler + + .weak DMA1_Stream7_IRQHandler + .thumb_set DMA1_Stream7_IRQHandler,Default_Handler + + .weak FMC_IRQHandler + .thumb_set FMC_IRQHandler,Default_Handler + + .weak SDMMC1_IRQHandler + .thumb_set SDMMC1_IRQHandler,Default_Handler + + .weak TIM5_IRQHandler + .thumb_set TIM5_IRQHandler,Default_Handler + + .weak SPI3_IRQHandler + .thumb_set SPI3_IRQHandler,Default_Handler + + .weak UART4_IRQHandler + .thumb_set UART4_IRQHandler,Default_Handler + + .weak UART5_IRQHandler + .thumb_set UART5_IRQHandler,Default_Handler + + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + + .weak DMA2_Stream0_IRQHandler + .thumb_set DMA2_Stream0_IRQHandler,Default_Handler + + .weak DMA2_Stream1_IRQHandler + .thumb_set DMA2_Stream1_IRQHandler,Default_Handler + + .weak DMA2_Stream2_IRQHandler + .thumb_set DMA2_Stream2_IRQHandler,Default_Handler + + .weak DMA2_Stream3_IRQHandler + .thumb_set DMA2_Stream3_IRQHandler,Default_Handler + + .weak DMA2_Stream4_IRQHandler + .thumb_set DMA2_Stream4_IRQHandler,Default_Handler + + .weak ETH_IRQHandler + .thumb_set ETH_IRQHandler,Default_Handler + + .weak ETH_WKUP_IRQHandler + .thumb_set ETH_WKUP_IRQHandler,Default_Handler + + .weak CAN2_TX_IRQHandler + .thumb_set CAN2_TX_IRQHandler,Default_Handler + + .weak CAN2_RX0_IRQHandler + .thumb_set CAN2_RX0_IRQHandler,Default_Handler + + .weak CAN2_RX1_IRQHandler + .thumb_set CAN2_RX1_IRQHandler,Default_Handler + + .weak CAN2_SCE_IRQHandler + .thumb_set CAN2_SCE_IRQHandler,Default_Handler + + .weak OTG_FS_IRQHandler + .thumb_set OTG_FS_IRQHandler,Default_Handler + + .weak DMA2_Stream5_IRQHandler + .thumb_set DMA2_Stream5_IRQHandler,Default_Handler + + .weak DMA2_Stream6_IRQHandler + .thumb_set DMA2_Stream6_IRQHandler,Default_Handler + + .weak DMA2_Stream7_IRQHandler + .thumb_set DMA2_Stream7_IRQHandler,Default_Handler + + .weak USART6_IRQHandler + .thumb_set USART6_IRQHandler,Default_Handler + + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_OUT_IRQHandler + .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_IN_IRQHandler + .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler + + .weak OTG_HS_WKUP_IRQHandler + .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler + + .weak OTG_HS_IRQHandler + .thumb_set OTG_HS_IRQHandler,Default_Handler + + .weak DCMI_IRQHandler + .thumb_set DCMI_IRQHandler,Default_Handler + + .weak HASH_RNG_IRQHandler + .thumb_set HASH_RNG_IRQHandler,Default_Handler + + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + + .weak UART7_IRQHandler + .thumb_set UART7_IRQHandler,Default_Handler + + .weak UART8_IRQHandler + .thumb_set UART8_IRQHandler,Default_Handler + + .weak SPI4_IRQHandler + .thumb_set SPI4_IRQHandler,Default_Handler + + .weak SPI5_IRQHandler + .thumb_set SPI5_IRQHandler,Default_Handler + + .weak SPI6_IRQHandler + .thumb_set SPI6_IRQHandler,Default_Handler + + .weak SAI1_IRQHandler + .thumb_set SAI1_IRQHandler,Default_Handler + + .weak DMA2D_IRQHandler + .thumb_set DMA2D_IRQHandler,Default_Handler + + .weak SAI2_IRQHandler + .thumb_set SAI2_IRQHandler,Default_Handler + + .weak QUADSPI_IRQHandler + .thumb_set QUADSPI_IRQHandler,Default_Handler + + .weak LPTIM1_IRQHandler + .thumb_set LPTIM1_IRQHandler,Default_Handler + + .weak CEC_IRQHandler + .thumb_set CEC_IRQHandler,Default_Handler + + .weak I2C4_EV_IRQHandler + .thumb_set I2C4_EV_IRQHandler,Default_Handler + + .weak I2C4_ER_IRQHandler + .thumb_set I2C4_ER_IRQHandler,Default_Handler + + .weak SPDIF_RX_IRQHandler + .thumb_set SPDIF_RX_IRQHandler,Default_Handler + + .weak DSIHOST_IRQHandler + .thumb_set DSIHOST_IRQHandler,Default_Handler + + .weak DFSDM1_FLT0_IRQHandler + .thumb_set DFSDM1_FLT0_IRQHandler,Default_Handler + + .weak DFSDM1_FLT1_IRQHandler + .thumb_set DFSDM1_FLT1_IRQHandler,Default_Handler + + .weak DFSDM1_FLT2_IRQHandler + .thumb_set DFSDM1_FLT2_IRQHandler,Default_Handler + + .weak DFSDM1_FLT3_IRQHandler + .thumb_set DFSDM1_FLT3_IRQHandler,Default_Handler + + .weak SDMMC2_IRQHandler + .thumb_set SDMMC2_IRQHandler,Default_Handler + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ From e3b81f5712a74ca2e186e70bb3236dd6b8957956 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Mon, 5 Mar 2018 18:04:06 +0200 Subject: [PATCH 431/828] stm32/boards: Add startup_stm32f4.s for F4 series specific startup. --- ports/stm32/boards/startup_stm32f4.s | 522 +++++++++++++++++++++++++++ 1 file changed, 522 insertions(+) create mode 100644 ports/stm32/boards/startup_stm32f4.s diff --git a/ports/stm32/boards/startup_stm32f4.s b/ports/stm32/boards/startup_stm32f4.s new file mode 100644 index 0000000000..e46a93b71a --- /dev/null +++ b/ports/stm32/boards/startup_stm32f4.s @@ -0,0 +1,522 @@ +/** + ****************************************************************************** + * @file startup_stm32.S + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief STM32Fxxxxx Devices vector table for Atollic TrueSTUDIO toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M4/M7 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m4 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss +/* stack used for SystemInit_ExtMemCtl; always internal RAM used */ + +/** + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval : None +*/ + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr sp, =_estack /* set stack pointer */ + +/* Copy the data segment initializers from flash to SRAM */ + movs r1, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r3, =_sidata + ldr r3, [r3, r1] + str r3, [r0, r1] + adds r1, r1, #4 + +LoopCopyDataInit: + ldr r0, =_sdata + ldr r3, =_edata + adds r2, r0, r1 + cmp r2, r3 + bcc CopyDataInit + ldr r2, =_sbss + b LoopFillZerobss +/* Zero fill the bss segment. */ +FillZerobss: + movs r3, #0 + str r3, [r2], #4 + +LoopFillZerobss: + ldr r3, = _ebss + cmp r2, r3 + bcc FillZerobss + +/* Call the clock system initialization function.*/ + bl SystemInit +/* Call static constructors */ + /*bl __libc_init_array*/ +/* Call the application's entry point.*/ + bl main + bx lr +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * @param None + * @retval None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex M4/M7. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +*******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + + /* External Interrupts */ + .word WWDG_IRQHandler /* Window WatchDog */ + .word PVD_IRQHandler /* PVD through EXTI Line detection */ + .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ + .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ + .word FLASH_IRQHandler /* FLASH */ + .word RCC_IRQHandler /* RCC */ + .word EXTI0_IRQHandler /* EXTI Line0 */ + .word EXTI1_IRQHandler /* EXTI Line1 */ + .word EXTI2_IRQHandler /* EXTI Line2 */ + .word EXTI3_IRQHandler /* EXTI Line3 */ + .word EXTI4_IRQHandler /* EXTI Line4 */ + .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */ + .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */ + .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */ + .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */ + .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */ + .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */ + .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */ + .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */ + .word CAN1_TX_IRQHandler /* CAN1 TX */ + .word CAN1_RX0_IRQHandler /* CAN1 RX0 */ + .word CAN1_RX1_IRQHandler /* CAN1 RX1 */ + .word CAN1_SCE_IRQHandler /* CAN1 SCE */ + .word EXTI9_5_IRQHandler /* External Line[9:5]s */ + .word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */ + .word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */ + .word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */ + .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ + .word TIM2_IRQHandler /* TIM2 */ + .word TIM3_IRQHandler /* TIM3 */ + .word TIM4_IRQHandler /* TIM4 */ + .word I2C1_EV_IRQHandler /* I2C1 Event */ + .word I2C1_ER_IRQHandler /* I2C1 Error */ + .word I2C2_EV_IRQHandler /* I2C2 Event */ + .word I2C2_ER_IRQHandler /* I2C2 Error */ + .word SPI1_IRQHandler /* SPI1 */ + .word SPI2_IRQHandler /* SPI2 */ + .word USART1_IRQHandler /* USART1 */ + .word USART2_IRQHandler /* USART2 */ + .word USART3_IRQHandler /* USART3 */ + .word EXTI15_10_IRQHandler /* External Line[15:10]s */ + .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ + .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */ + .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */ + .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */ + .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */ + .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ + .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */ + .word FSMC_IRQHandler /* FSMC */ + .word SDIO_IRQHandler /* SDIO */ + .word TIM5_IRQHandler /* TIM5 */ + .word SPI3_IRQHandler /* SPI3 */ + .word UART4_IRQHandler /* UART4 */ + .word UART5_IRQHandler /* UART5 */ + .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */ + .word TIM7_IRQHandler /* TIM7 */ + .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */ + .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */ + .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */ + .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */ + .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */ + .word ETH_IRQHandler /* Ethernet */ + .word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */ + .word CAN2_TX_IRQHandler /* CAN2 TX */ + .word CAN2_RX0_IRQHandler /* CAN2 RX0 */ + .word CAN2_RX1_IRQHandler /* CAN2 RX1 */ + .word CAN2_SCE_IRQHandler /* CAN2 SCE */ + .word OTG_FS_IRQHandler /* USB OTG FS */ + .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */ + .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */ + .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */ + .word USART6_IRQHandler /* USART6 */ + .word I2C3_EV_IRQHandler /* I2C3 event */ + .word I2C3_ER_IRQHandler /* I2C3 error */ + .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */ + .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */ + .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */ + .word OTG_HS_IRQHandler /* USB OTG HS */ + .word DCMI_IRQHandler /* DCMI */ + .word 0 /* CRYP crypto */ + .word HASH_RNG_IRQHandler /* Hash and Rng */ + .word FPU_IRQHandler /* FPU */ + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_IRQHandler + .thumb_set PVD_IRQHandler,Default_Handler + + .weak TAMP_STAMP_IRQHandler + .thumb_set TAMP_STAMP_IRQHandler,Default_Handler + + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + + .weak DMA1_Stream0_IRQHandler + .thumb_set DMA1_Stream0_IRQHandler,Default_Handler + + .weak DMA1_Stream1_IRQHandler + .thumb_set DMA1_Stream1_IRQHandler,Default_Handler + + .weak DMA1_Stream2_IRQHandler + .thumb_set DMA1_Stream2_IRQHandler,Default_Handler + + .weak DMA1_Stream3_IRQHandler + .thumb_set DMA1_Stream3_IRQHandler,Default_Handler + + .weak DMA1_Stream4_IRQHandler + .thumb_set DMA1_Stream4_IRQHandler,Default_Handler + + .weak DMA1_Stream5_IRQHandler + .thumb_set DMA1_Stream5_IRQHandler,Default_Handler + + .weak DMA1_Stream6_IRQHandler + .thumb_set DMA1_Stream6_IRQHandler,Default_Handler + + .weak ADC_IRQHandler + .thumb_set ADC_IRQHandler,Default_Handler + + .weak CAN1_TX_IRQHandler + .thumb_set CAN1_TX_IRQHandler,Default_Handler + + .weak CAN1_RX0_IRQHandler + .thumb_set CAN1_RX0_IRQHandler,Default_Handler + + .weak CAN1_RX1_IRQHandler + .thumb_set CAN1_RX1_IRQHandler,Default_Handler + + .weak CAN1_SCE_IRQHandler + .thumb_set CAN1_SCE_IRQHandler,Default_Handler + + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + + .weak TIM1_BRK_TIM9_IRQHandler + .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler + + .weak TIM1_UP_TIM10_IRQHandler + .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_TIM11_IRQHandler + .thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + + .weak TIM4_IRQHandler + .thumb_set TIM4_IRQHandler,Default_Handler + + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + + .weak I2C2_EV_IRQHandler + .thumb_set I2C2_EV_IRQHandler,Default_Handler + + .weak I2C2_ER_IRQHandler + .thumb_set I2C2_ER_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + + .weak USART3_IRQHandler + .thumb_set USART3_IRQHandler,Default_Handler + + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + + .weak OTG_FS_WKUP_IRQHandler + .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler + + .weak TIM8_BRK_TIM12_IRQHandler + .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler + + .weak TIM8_UP_TIM13_IRQHandler + .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler + + .weak TIM8_TRG_COM_TIM14_IRQHandler + .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler + + .weak TIM8_CC_IRQHandler + .thumb_set TIM8_CC_IRQHandler,Default_Handler + + .weak DMA1_Stream7_IRQHandler + .thumb_set DMA1_Stream7_IRQHandler,Default_Handler + + .weak FSMC_IRQHandler + .thumb_set FSMC_IRQHandler,Default_Handler + + .weak SDIO_IRQHandler + .thumb_set SDIO_IRQHandler,Default_Handler + + .weak TIM5_IRQHandler + .thumb_set TIM5_IRQHandler,Default_Handler + + .weak SPI3_IRQHandler + .thumb_set SPI3_IRQHandler,Default_Handler + + .weak UART4_IRQHandler + .thumb_set UART4_IRQHandler,Default_Handler + + .weak UART5_IRQHandler + .thumb_set UART5_IRQHandler,Default_Handler + + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + + .weak DMA2_Stream0_IRQHandler + .thumb_set DMA2_Stream0_IRQHandler,Default_Handler + + .weak DMA2_Stream1_IRQHandler + .thumb_set DMA2_Stream1_IRQHandler,Default_Handler + + .weak DMA2_Stream2_IRQHandler + .thumb_set DMA2_Stream2_IRQHandler,Default_Handler + + .weak DMA2_Stream3_IRQHandler + .thumb_set DMA2_Stream3_IRQHandler,Default_Handler + + .weak DMA2_Stream4_IRQHandler + .thumb_set DMA2_Stream4_IRQHandler,Default_Handler + + .weak ETH_IRQHandler + .thumb_set ETH_IRQHandler,Default_Handler + + .weak ETH_WKUP_IRQHandler + .thumb_set ETH_WKUP_IRQHandler,Default_Handler + + .weak CAN2_TX_IRQHandler + .thumb_set CAN2_TX_IRQHandler,Default_Handler + + .weak CAN2_RX0_IRQHandler + .thumb_set CAN2_RX0_IRQHandler,Default_Handler + + .weak CAN2_RX1_IRQHandler + .thumb_set CAN2_RX1_IRQHandler,Default_Handler + + .weak CAN2_SCE_IRQHandler + .thumb_set CAN2_SCE_IRQHandler,Default_Handler + + .weak OTG_FS_IRQHandler + .thumb_set OTG_FS_IRQHandler,Default_Handler + + .weak DMA2_Stream5_IRQHandler + .thumb_set DMA2_Stream5_IRQHandler,Default_Handler + + .weak DMA2_Stream6_IRQHandler + .thumb_set DMA2_Stream6_IRQHandler,Default_Handler + + .weak DMA2_Stream7_IRQHandler + .thumb_set DMA2_Stream7_IRQHandler,Default_Handler + + .weak USART6_IRQHandler + .thumb_set USART6_IRQHandler,Default_Handler + + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_OUT_IRQHandler + .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_IN_IRQHandler + .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler + + .weak OTG_HS_WKUP_IRQHandler + .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler + + .weak OTG_HS_IRQHandler + .thumb_set OTG_HS_IRQHandler,Default_Handler + + .weak DCMI_IRQHandler + .thumb_set DCMI_IRQHandler,Default_Handler + + .weak HASH_RNG_IRQHandler + .thumb_set HASH_RNG_IRQHandler,Default_Handler + + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ From 88157715dbc423964eeb906648f5511d764b6578 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Mon, 5 Mar 2018 18:09:08 +0200 Subject: [PATCH 432/828] stm32/boards: Add startup_stm32l4.s for L4 series specific startup. --- ports/stm32/boards/startup_stm32l4.s | 522 +++++++++++++++++++++++++++ 1 file changed, 522 insertions(+) create mode 100644 ports/stm32/boards/startup_stm32l4.s diff --git a/ports/stm32/boards/startup_stm32l4.s b/ports/stm32/boards/startup_stm32l4.s new file mode 100644 index 0000000000..83af6d09ad --- /dev/null +++ b/ports/stm32/boards/startup_stm32l4.s @@ -0,0 +1,522 @@ +/** + ****************************************************************************** + * @file startup_stm32.S + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief STM32Fxxxxx Devices vector table for Atollic TrueSTUDIO toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M4/M7 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m4 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss +/* stack used for SystemInit_ExtMemCtl; always internal RAM used */ + +/** + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval : None +*/ + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr sp, =_estack /* set stack pointer */ + +/* Copy the data segment initializers from flash to SRAM */ + movs r1, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r3, =_sidata + ldr r3, [r3, r1] + str r3, [r0, r1] + adds r1, r1, #4 + +LoopCopyDataInit: + ldr r0, =_sdata + ldr r3, =_edata + adds r2, r0, r1 + cmp r2, r3 + bcc CopyDataInit + ldr r2, =_sbss + b LoopFillZerobss +/* Zero fill the bss segment. */ +FillZerobss: + movs r3, #0 + str r3, [r2], #4 + +LoopFillZerobss: + ldr r3, = _ebss + cmp r2, r3 + bcc FillZerobss + +/* Call the clock system initialization function.*/ + bl SystemInit +/* Call static constructors */ + /*bl __libc_init_array*/ +/* Call the application's entry point.*/ + bl main + bx lr +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * @param None + * @retval None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex M4/M7. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +*******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + + /* External Interrupts */ + .word WWDG_IRQHandler /* Window WatchDog */ + .word PVD_PVM_IRQHandler /* PVD and PVM through EXTI line detection */ + .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ + .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ + .word FLASH_IRQHandler /* FLASH */ + .word RCC_IRQHandler /* RCC */ + .word EXTI0_IRQHandler /* EXTI Line0 */ + .word EXTI1_IRQHandler /* EXTI Line1 */ + .word EXTI2_IRQHandler /* EXTI Line2 */ + .word EXTI3_IRQHandler /* EXTI Line3 */ + .word EXTI4_IRQHandler /* EXTI Line4 */ + .word DMA1_Channel1_IRQHandler /* DMA1 Channel 1 */ + .word DMA1_Channel2_IRQHandler /* DMA1 Channel 2 */ + .word DMA1_Channel3_IRQHandler /* DMA1 Channel 3 */ + .word DMA1_Channel4_IRQHandler /* DMA1 Channel 4 */ + .word DMA1_Channel5_IRQHandler /* DMA1 Channel 5 */ + .word DMA1_Channel6_IRQHandler /* DMA1 Channel 6 */ + .word DMA1_Channel7_IRQHandler /* DMA1 Channel 7 */ + .word ADC1_2_IRQHandler /* ADC1 and ADC2 */ + .word CAN1_TX_IRQHandler /* CAN1 TX */ + .word CAN1_RX0_IRQHandler /* CAN1 RX0 */ + .word CAN1_RX1_IRQHandler /* CAN1 RX1 */ + .word CAN1_SCE_IRQHandler /* CAN1 SCE */ + .word EXTI9_5_IRQHandler /* External Line[9:5]s */ + .word TIM1_BRK_TIM15_IRQHandler /* TIM1 Break and TIM15 */ + .word TIM1_UP_TIM16_IRQHandler /* TIM1 Update and TIM16 */ + .word TIM1_TRG_COM_TIM17_IRQHandler /* TIM1 Trigger and Commutation and TIM17 */ + .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ + .word TIM2_IRQHandler /* TIM2 */ + .word TIM3_IRQHandler /* TIM3 */ + .word TIM4_IRQHandler /* TIM4 */ + .word I2C1_EV_IRQHandler /* I2C1 Event */ + .word I2C1_ER_IRQHandler /* I2C1 Error */ + .word I2C2_EV_IRQHandler /* I2C2 Event */ + .word I2C2_ER_IRQHandler /* I2C2 Error */ + .word SPI1_IRQHandler /* SPI1 */ + .word SPI2_IRQHandler /* SPI2 */ + .word USART1_IRQHandler /* USART1 */ + .word USART2_IRQHandler /* USART2 */ + .word USART3_IRQHandler /* USART3 */ + .word EXTI15_10_IRQHandler /* External Line[15:10]s */ + .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ + .word DFSDM3_IRQHandler /* Digital filter for sigma delta modulator 3 */ + .word TIM8_BRK_IRQHandler /* TIM8 Break */ + .word TIM8_UP_IRQHandler /* TIM8 Update */ + .word TIM8_TRG_COM_IRQHandler /* TIM8 Trigger and Commutation */ + .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ + .word ADC3_IRQHandler /* ADC3 global interrupt */ + .word FMC_IRQHandler /* FMC */ + .word SDMMC1_IRQHandler /* SDMMC1 */ + .word TIM5_IRQHandler /* TIM5 */ + .word SPI3_IRQHandler /* SPI3 */ + .word UART4_IRQHandler /* UART4 */ + .word UART5_IRQHandler /* UART5 */ + .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */ + .word TIM7_IRQHandler /* TIM7 */ + .word DMA2_Channel1_IRQHandler /* DMA2 Channel 1 */ + .word DMA2_Channel2_IRQHandler /* DMA2 Channel 2 */ + .word DMA2_Channel3_IRQHandler /* DMA2 Channel 3 */ + .word DMA2_Channel4_IRQHandler /* DMA2 Channel 4 */ + .word DMA2_Channel5_IRQHandler /* DMA2 Channel 5 */ + .word DFSDM0_IRQHandler /* Digital filter for sigma delta modulator 0 */ + .word DFSDM1_IRQHandler /* Digital filter for sigma delta modulator 1 */ + .word DFSDM2_IRQHandler /* Digital filter for sigma delta modulator 2 */ + .word COMP_IRQHandler /* Comporator thru EXTI line */ + .word LPTIM1_IRQHandler /* Low power timer 1 */ + .word LPTIM2_IRQHandler /* Low power timer 2 */ + .word OTG_FS_IRQHandler /* USB OTG FS */ + .word DMA2_Channel6_IRQHandler /* DMA2 Channel 6 */ + .word DMA2_Channel7_IRQHandler /* DMA2 Channel 7 */ + .word LPUART1_IRQHandler /* Low power UART */ + .word QUADSPI_IRQHandler /* Quad SPI */ + .word I2C3_EV_IRQHandler /* I2C3 event */ + .word I2C3_ER_IRQHandler /* I2C3 error */ + .word SAI1_IRQHandler /* Serial audio interface 1 */ + .word SAI2_IRQHandler /* Serial audio interface 2 */ + .word SWPMI1_IRQHandler /* Single wire protocole 1 */ + .word TSC_IRQHandler /* Touch sensig controller */ + .word LCD_IRQHandler /* LCD */ + .word 0 /* CRYP crypto */ + .word RNG_IRQHandler /* Random number generator */ + .word FPU_IRQHandler /* FPU */ + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_PVM_IRQHandler + .thumb_set PVD_PVM_IRQHandler,Default_Handler + + .weak TAMP_STAMP_IRQHandler + .thumb_set TAMP_STAMP_IRQHandler,Default_Handler + + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + + .weak DMA1_Channel1_IRQHandler + .thumb_set DMA1_Channel1_IRQHandler,Default_Handler + + .weak DMA1_Channel2_IRQHandler + .thumb_set DMA1_Channel2_IRQHandler,Default_Handler + + .weak DMA1_Channel3_IRQHandler + .thumb_set DMA1_Channel3_IRQHandler,Default_Handler + + .weak DMA1_Channel4_IRQHandler + .thumb_set DMA1_Channel4_IRQHandler,Default_Handler + + .weak DMA1_Channel5_IRQHandler + .thumb_set DMA1_Channel5_IRQHandler,Default_Handler + + .weak DMA1_Channel6_IRQHandler + .thumb_set DMA1_Channel6_IRQHandler,Default_Handler + + .weak DMA1_Channel7_IRQHandler + .thumb_set DMA1_Channel7_IRQHandler,Default_Handler + + .weak ADC1_2_IRQHandler + .thumb_set ADC1_2_IRQHandler,Default_Handler + + .weak CAN1_TX_IRQHandler + .thumb_set CAN1_TX_IRQHandler,Default_Handler + + .weak CAN1_RX0_IRQHandler + .thumb_set CAN1_RX0_IRQHandler,Default_Handler + + .weak CAN1_RX1_IRQHandler + .thumb_set CAN1_RX1_IRQHandler,Default_Handler + + .weak CAN1_SCE_IRQHandler + .thumb_set CAN1_SCE_IRQHandler,Default_Handler + + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + + .weak TIM1_BRK_TIM15_IRQHandler + .thumb_set TIM1_BRK_TIM15_IRQHandler,Default_Handler + + .weak TIM1_UP_TIM16_IRQHandler + .thumb_set TIM1_UP_TIM16_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_TIM17_IRQHandler + .thumb_set TIM1_TRG_COM_TIM17_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + + .weak TIM4_IRQHandler + .thumb_set TIM4_IRQHandler,Default_Handler + + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + + .weak I2C2_EV_IRQHandler + .thumb_set I2C2_EV_IRQHandler,Default_Handler + + .weak I2C2_ER_IRQHandler + .thumb_set I2C2_ER_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + + .weak USART3_IRQHandler + .thumb_set USART3_IRQHandler,Default_Handler + + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + + .weak DFSDM3_IRQHandler + .thumb_set DFSDM3_IRQHandler,Default_Handler + + .weak TIM8_BRK_IRQHandler + .thumb_set TIM8_BRK_IRQHandler,Default_Handler + + .weak TIM8_UP_IRQHandler + .thumb_set TIM8_UP_IRQHandler,Default_Handler + + .weak TIM8_TRG_COM_IRQHandler + .thumb_set TIM8_TRG_COM_IRQHandler,Default_Handler + + .weak TIM8_CC_IRQHandler + .thumb_set TIM8_CC_IRQHandler,Default_Handler + + .weak ADC3_IRQHandler + .thumb_set ADC3_IRQHandler,Default_Handler + + .weak FMC_IRQHandler + .thumb_set FMC_IRQHandler,Default_Handler + + .weak SDMMC1_IRQHandler + .thumb_set SDMMC1_IRQHandler,Default_Handler + + .weak TIM5_IRQHandler + .thumb_set TIM5_IRQHandler,Default_Handler + + .weak SPI3_IRQHandler + .thumb_set SPI3_IRQHandler,Default_Handler + + .weak UART4_IRQHandler + .thumb_set UART4_IRQHandler,Default_Handler + + .weak UART5_IRQHandler + .thumb_set UART5_IRQHandler,Default_Handler + + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + + .weak DMA2_Channel1_IRQHandler + .thumb_set DMA2_Channel1_IRQHandler,Default_Handler + + .weak DMA2_Channel2_IRQHandler + .thumb_set DMA2_Channel2_IRQHandler,Default_Handler + + .weak DMA2_Channel3_IRQHandler + .thumb_set DMA2_Channel3_IRQHandler,Default_Handler + + .weak DMA2_Channel4_IRQHandler + .thumb_set DMA2_Channel4_IRQHandler,Default_Handler + + .weak DMA2_Channel5_IRQHandler + .thumb_set DMA2_Channel5_IRQHandler,Default_Handler + + .weak DFSDM0_IRQHandler + .thumb_set DFSDM0_IRQHandler,Default_Handler + + .weak DFSDM1_IRQHandler + .thumb_set DFSDM1_IRQHandler,Default_Handler + + .weak DFSDM2_IRQHandler + .thumb_set DFSDM2_IRQHandler,Default_Handler + + .weak COMP_IRQHandler + .thumb_set COMP_IRQHandler,Default_Handler + + .weak LPTIM1_IRQHandler + .thumb_set LPTIM1_IRQHandler,Default_Handler + + .weak LPTIM2_IRQHandler + .thumb_set LPTIM2_IRQHandler,Default_Handler + + .weak OTG_FS_IRQHandler + .thumb_set OTG_FS_IRQHandler,Default_Handler + + .weak DMA2_Channel6_IRQHandler + .thumb_set DMA2_Channel6_IRQHandler,Default_Handler + + .weak DMA2_Channel7_IRQHandler + .thumb_set DMA2_Channel7_IRQHandler,Default_Handler + + .weak LPUART1_IRQHandler + .thumb_set LPUART1_IRQHandler,Default_Handler + + .weak QUADSPI_IRQHandler + .thumb_set QUADSPI_IRQHandler,Default_Handler + + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + + .weak SAI1_IRQHandler + .thumb_set SAI1_IRQHandler,Default_Handler + + .weak SAI2_IRQHandler + .thumb_set SAI2_IRQHandler,Default_Handler + + .weak SWPMI1_IRQHandler + .thumb_set SWPMI1_IRQHandler,Default_Handler + + .weak TSC_IRQHandler + .thumb_set TSC_IRQHandler,Default_Handler + + .weak LCD_IRQHandler + .thumb_set LCD_IRQHandler,Default_Handler + + .weak RNG_IRQHandler + .thumb_set RNG_IRQHandler,Default_Handler + + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ From 66748aaf60ae8bc4dabfeedcb922e284a8ec34f5 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Mon, 5 Mar 2018 18:09:41 +0200 Subject: [PATCH 433/828] stm32/Makefile: Use separate startup file for each MCU series. --- ports/stm32/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 5e4ec9f6f8..112093f844 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -37,6 +37,7 @@ DEVICE=0483:df11 STFLASH ?= st-flash OPENOCD ?= openocd OPENOCD_CONFIG ?= boards/openocd_stm32f4.cfg +STARTUP_FILE ?= boards/startup_stm32$(MCU_SERIES).o CROSS_COMPILE = arm-none-eabi- @@ -248,7 +249,7 @@ SRC_C = \ $(wildcard boards/$(BOARD)/*.c) SRC_O = \ - startup_stm32.o \ + $(STARTUP_FILE) \ gchelper.o \ $(BUILD)/$(HAL_DIR)/Src/%.o: CFLAGS += -fno-strict-aliasing From eb56efb4347265678c90bd67a8ea3c89b1d052eb Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 9 Mar 2018 15:06:27 +1100 Subject: [PATCH 434/828] stm32: Remove startup_stm32.S, now provided in boards/ for each MCU. --- ports/stm32/startup_stm32.S | 822 ------------------------------------ 1 file changed, 822 deletions(-) delete mode 100644 ports/stm32/startup_stm32.S diff --git a/ports/stm32/startup_stm32.S b/ports/stm32/startup_stm32.S deleted file mode 100644 index a688cd0673..0000000000 --- a/ports/stm32/startup_stm32.S +++ /dev/null @@ -1,822 +0,0 @@ -/** - ****************************************************************************** - * @file startup_stm32.S - * @author MCD Application Team - * @version V2.0.0 - * @date 18-February-2014 - * @brief STM32Fxxxxx Devices vector table for Atollic TrueSTUDIO toolchain. - * This module performs: - * - Set the initial SP - * - Set the initial PC == Reset_Handler, - * - Set the vector table entries with the exceptions ISR address - * - Branches to main in the C library (which eventually - * calls main()). - * After Reset the Cortex-M4/M7 processor is in Thread mode, - * priority is Privileged, and the Stack is set to Main. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT 2014 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - - .syntax unified -#if defined(MCU_SERIES_F7) - .cpu cortex-m7 -#elif defined(MCU_SERIES_F4) || defined(MCU_SERIES_L4) - .cpu cortex-m4 -#else - #error "Unknown MCU Series" -#endif - .fpu softvfp - .thumb - -.global g_pfnVectors -.global Default_Handler - -/* start address for the initialization values of the .data section. -defined in linker script */ -.word _sidata -/* start address for the .data section. defined in linker script */ -.word _sdata -/* end address for the .data section. defined in linker script */ -.word _edata -/* start address for the .bss section. defined in linker script */ -.word _sbss -/* end address for the .bss section. defined in linker script */ -.word _ebss -/* stack used for SystemInit_ExtMemCtl; always internal RAM used */ - -/** - * @brief This is the code that gets called when the processor first - * starts execution following a reset event. Only the absolutely - * necessary set is performed, after which the application - * supplied main() routine is called. - * @param None - * @retval : None -*/ - - .section .text.Reset_Handler - .weak Reset_Handler - .type Reset_Handler, %function -Reset_Handler: - ldr sp, =_estack /* set stack pointer */ - -/* Copy the data segment initializers from flash to SRAM */ - movs r1, #0 - b LoopCopyDataInit - -CopyDataInit: - ldr r3, =_sidata - ldr r3, [r3, r1] - str r3, [r0, r1] - adds r1, r1, #4 - -LoopCopyDataInit: - ldr r0, =_sdata - ldr r3, =_edata - adds r2, r0, r1 - cmp r2, r3 - bcc CopyDataInit - ldr r2, =_sbss - b LoopFillZerobss -/* Zero fill the bss segment. */ -FillZerobss: - movs r3, #0 - str r3, [r2], #4 - -LoopFillZerobss: - ldr r3, = _ebss - cmp r2, r3 - bcc FillZerobss - -/* Call the clock system initialization function.*/ - bl SystemInit -/* Call static constructors */ - /*bl __libc_init_array*/ -/* Call the application's entry point.*/ - bl main - bx lr -.size Reset_Handler, .-Reset_Handler - -/** - * @brief This is the code that gets called when the processor receives an - * unexpected interrupt. This simply enters an infinite loop, preserving - * the system state for examination by a debugger. - * @param None - * @retval None -*/ - .section .text.Default_Handler,"ax",%progbits -Default_Handler: -Infinite_Loop: - b Infinite_Loop - .size Default_Handler, .-Default_Handler -/****************************************************************************** -* -* The minimal vector table for a Cortex M4/M7. Note that the proper constructs -* must be placed on this to ensure that it ends up at physical address -* 0x0000.0000. -* -*******************************************************************************/ - .section .isr_vector,"a",%progbits - .type g_pfnVectors, %object - .size g_pfnVectors, .-g_pfnVectors - - -g_pfnVectors: - .word _estack - .word Reset_Handler - .word NMI_Handler - .word HardFault_Handler - .word MemManage_Handler - .word BusFault_Handler - .word UsageFault_Handler - .word 0 - .word 0 - .word 0 - .word 0 - .word SVC_Handler - .word DebugMon_Handler - .word 0 - .word PendSV_Handler - .word SysTick_Handler - - /* External Interrupts */ - .word WWDG_IRQHandler /* Window WatchDog */ -#if defined(MCU_SERIES_L4) - .word PVD_PVM_IRQHandler /* PVD and PVM through EXTI line detection */ -#else - .word PVD_IRQHandler /* PVD through EXTI Line detection */ -#endif - .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ - .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ - .word FLASH_IRQHandler /* FLASH */ - .word RCC_IRQHandler /* RCC */ - .word EXTI0_IRQHandler /* EXTI Line0 */ - .word EXTI1_IRQHandler /* EXTI Line1 */ - .word EXTI2_IRQHandler /* EXTI Line2 */ - .word EXTI3_IRQHandler /* EXTI Line3 */ - .word EXTI4_IRQHandler /* EXTI Line4 */ -#if defined(MCU_SERIES_L4) - .word DMA1_Channel1_IRQHandler /* DMA1 Channel 1 */ - .word DMA1_Channel2_IRQHandler /* DMA1 Channel 2 */ - .word DMA1_Channel3_IRQHandler /* DMA1 Channel 3 */ - .word DMA1_Channel4_IRQHandler /* DMA1 Channel 4 */ - .word DMA1_Channel5_IRQHandler /* DMA1 Channel 5 */ - .word DMA1_Channel6_IRQHandler /* DMA1 Channel 6 */ - .word DMA1_Channel7_IRQHandler /* DMA1 Channel 7 */ - .word ADC1_2_IRQHandler /* ADC1 and ADC2 */ -#else - .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */ - .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */ - .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */ - .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */ - .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */ - .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */ - .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */ - .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */ -#endif - .word CAN1_TX_IRQHandler /* CAN1 TX */ - .word CAN1_RX0_IRQHandler /* CAN1 RX0 */ - .word CAN1_RX1_IRQHandler /* CAN1 RX1 */ - .word CAN1_SCE_IRQHandler /* CAN1 SCE */ - .word EXTI9_5_IRQHandler /* External Line[9:5]s */ -#if defined(MCU_SERIES_L4) - .word TIM1_BRK_TIM15_IRQHandler /* TIM1 Break and TIM15 */ - .word TIM1_UP_TIM16_IRQHandler /* TIM1 Update and TIM16 */ - .word TIM1_TRG_COM_TIM17_IRQHandler /* TIM1 Trigger and Commutation and TIM17 */ -#else - .word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */ - .word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */ - .word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */ -#endif - .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ - .word TIM2_IRQHandler /* TIM2 */ - .word TIM3_IRQHandler /* TIM3 */ - .word TIM4_IRQHandler /* TIM4 */ - .word I2C1_EV_IRQHandler /* I2C1 Event */ - .word I2C1_ER_IRQHandler /* I2C1 Error */ - .word I2C2_EV_IRQHandler /* I2C2 Event */ - .word I2C2_ER_IRQHandler /* I2C2 Error */ - .word SPI1_IRQHandler /* SPI1 */ - .word SPI2_IRQHandler /* SPI2 */ - .word USART1_IRQHandler /* USART1 */ - .word USART2_IRQHandler /* USART2 */ - .word USART3_IRQHandler /* USART3 */ - .word EXTI15_10_IRQHandler /* External Line[15:10]s */ - .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ -#if defined(MCU_SERIES_L4) - .word DFSDM3_IRQHandler /* Digital filter for sigma delta modulator 3 */ - .word TIM8_BRK_IRQHandler /* TIM8 Break */ - .word TIM8_UP_IRQHandler /* TIM8 Update */ - .word TIM8_TRG_COM_IRQHandler /* TIM8 Trigger and Commutation */ -#else - .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */ - .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */ - .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */ - .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */ -#endif - .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ -#if defined(MCU_SERIES_L4) - .word ADC3_IRQHandler /* ADC3 global interrupt */ -#else - .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */ -#endif -#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) - .word FMC_IRQHandler /* FMC */ - .word SDMMC1_IRQHandler /* SDMMC1 */ -#else - .word FSMC_IRQHandler /* FSMC */ - .word SDIO_IRQHandler /* SDIO */ -#endif - .word TIM5_IRQHandler /* TIM5 */ - .word SPI3_IRQHandler /* SPI3 */ - .word UART4_IRQHandler /* UART4 */ - .word UART5_IRQHandler /* UART5 */ - .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */ - .word TIM7_IRQHandler /* TIM7 */ -#if defined(MCU_SERIES_L4) - .word DMA2_Channel1_IRQHandler /* DMA2 Channel 1 */ - .word DMA2_Channel2_IRQHandler /* DMA2 Channel 2 */ - .word DMA2_Channel3_IRQHandler /* DMA2 Channel 3 */ - .word DMA2_Channel4_IRQHandler /* DMA2 Channel 4 */ - .word DMA2_Channel5_IRQHandler /* DMA2 Channel 5 */ - .word DFSDM0_IRQHandler /* Digital filter for sigma delta modulator 0 */ - .word DFSDM1_IRQHandler /* Digital filter for sigma delta modulator 1 */ - .word DFSDM2_IRQHandler /* Digital filter for sigma delta modulator 2 */ - .word COMP_IRQHandler /* Comporator thru EXTI line */ - .word LPTIM1_IRQHandler /* Low power timer 1 */ - .word LPTIM2_IRQHandler /* Low power timer 2 */ -#else - .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */ - .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */ - .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */ - .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */ - .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */ - .word ETH_IRQHandler /* Ethernet */ - .word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */ - .word CAN2_TX_IRQHandler /* CAN2 TX */ - .word CAN2_RX0_IRQHandler /* CAN2 RX0 */ - .word CAN2_RX1_IRQHandler /* CAN2 RX1 */ - .word CAN2_SCE_IRQHandler /* CAN2 SCE */ -#endif - .word OTG_FS_IRQHandler /* USB OTG FS */ -#if defined(MCU_SERIES_L4) - .word DMA2_Channel6_IRQHandler /* DMA2 Channel 6 */ - .word DMA2_Channel7_IRQHandler /* DMA2 Channel 7 */ - .word LPUART1_IRQHandler /* Low power UART */ - .word QUADSPI_IRQHandler /* Quad SPI */ -#else - .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */ - .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */ - .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */ - .word USART6_IRQHandler /* USART6 */ -#endif - .word I2C3_EV_IRQHandler /* I2C3 event */ - .word I2C3_ER_IRQHandler /* I2C3 error */ -#if defined(MCU_SERIES_L4) - .word SAI1_IRQHandler /* Serial audio interface 1 */ - .word SAI2_IRQHandler /* Serial audio interface 2 */ - .word SWPMI1_IRQHandler /* Single wire protocole 1 */ - .word TSC_IRQHandler /* Touch sensig controller */ - .word LCD_IRQHandler /* LCD */ -#else - .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */ - .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */ - .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */ - .word OTG_HS_IRQHandler /* USB OTG HS */ - .word DCMI_IRQHandler /* DCMI */ -#endif - .word 0 /* CRYP crypto */ -#if defined(MCU_SERIES_L4) - .word RNG_IRQHandler /* Random number generator */ -#else - .word HASH_RNG_IRQHandler /* Hash and Rng */ -#endif - .word FPU_IRQHandler /* FPU */ - -#if defined(MCU_SERIES_F7) - .word UART7_IRQHandler /* UART7 */ - .word UART8_IRQHandler /* UART8 */ - .word SPI4_IRQHandler /* SPI4 */ - .word SPI5_IRQHandler /* SPI5 */ - .word SPI6_IRQHandler /* SPI6 */ - .word SAI1_IRQHandler /* SAI1 */ - .word 0 /* Reserved */ - .word 0 /* Reserved */ - .word DMA2D_IRQHandler /* DMA2D */ - .word SAI2_IRQHandler /* SAI2 */ - .word QUADSPI_IRQHandler /* QUADSPI */ - .word LPTIM1_IRQHandler /* LPTIM1 */ - .word CEC_IRQHandler /* HDMI_CEC */ - .word I2C4_EV_IRQHandler /* I2C4 Event */ - .word I2C4_ER_IRQHandler /* I2C4 Error */ - .word SPDIF_RX_IRQHandler /* SPDIF_RX */ - .word DSIHOST_IRQHandler /* DSI host */ - .word DFSDM1_FLT0_IRQHandler /* DFSDM1 filter 0 */ - .word DFSDM1_FLT1_IRQHandler /* DFSDM1 filter 1 */ - .word DFSDM1_FLT2_IRQHandler /* DFSDM1 filter 2 */ - .word DFSDM1_FLT3_IRQHandler /* DFSDM1 filter 3 */ - .word SDMMC2_IRQHandler /* SDMMC2 */ -#endif - -/******************************************************************************* -* -* Provide weak aliases for each Exception handler to the Default_Handler. -* As they are weak aliases, any function with the same name will override -* this definition. -* -*******************************************************************************/ - .weak NMI_Handler - .thumb_set NMI_Handler,Default_Handler - - .weak HardFault_Handler - .thumb_set HardFault_Handler,Default_Handler - - .weak MemManage_Handler - .thumb_set MemManage_Handler,Default_Handler - - .weak BusFault_Handler - .thumb_set BusFault_Handler,Default_Handler - - .weak UsageFault_Handler - .thumb_set UsageFault_Handler,Default_Handler - - .weak SVC_Handler - .thumb_set SVC_Handler,Default_Handler - - .weak DebugMon_Handler - .thumb_set DebugMon_Handler,Default_Handler - - .weak PendSV_Handler - .thumb_set PendSV_Handler,Default_Handler - - .weak SysTick_Handler - .thumb_set SysTick_Handler,Default_Handler - - .weak WWDG_IRQHandler - .thumb_set WWDG_IRQHandler,Default_Handler - -#if defined(MCU_SERIES_L4) - .weak PVD_PVM_IRQHandler - .thumb_set PVD_PVM_IRQHandler,Default_Handler -#else - .weak PVD_IRQHandler - .thumb_set PVD_IRQHandler,Default_Handler -#endif - - .weak TAMP_STAMP_IRQHandler - .thumb_set TAMP_STAMP_IRQHandler,Default_Handler - - .weak RTC_WKUP_IRQHandler - .thumb_set RTC_WKUP_IRQHandler,Default_Handler - - .weak FLASH_IRQHandler - .thumb_set FLASH_IRQHandler,Default_Handler - - .weak RCC_IRQHandler - .thumb_set RCC_IRQHandler,Default_Handler - - .weak EXTI0_IRQHandler - .thumb_set EXTI0_IRQHandler,Default_Handler - - .weak EXTI1_IRQHandler - .thumb_set EXTI1_IRQHandler,Default_Handler - - .weak EXTI2_IRQHandler - .thumb_set EXTI2_IRQHandler,Default_Handler - - .weak EXTI3_IRQHandler - .thumb_set EXTI3_IRQHandler,Default_Handler - - .weak EXTI4_IRQHandler - .thumb_set EXTI4_IRQHandler,Default_Handler - -#if defined(MCU_SERIES_L4) - .weak DMA1_Channel1_IRQHandler - .thumb_set DMA1_Channel1_IRQHandler,Default_Handler - - .weak DMA1_Channel2_IRQHandler - .thumb_set DMA1_Channel2_IRQHandler,Default_Handler - - .weak DMA1_Channel3_IRQHandler - .thumb_set DMA1_Channel3_IRQHandler,Default_Handler - - .weak DMA1_Channel4_IRQHandler - .thumb_set DMA1_Channel4_IRQHandler,Default_Handler - - .weak DMA1_Channel5_IRQHandler - .thumb_set DMA1_Channel5_IRQHandler,Default_Handler - - .weak DMA1_Channel6_IRQHandler - .thumb_set DMA1_Channel6_IRQHandler,Default_Handler - - .weak DMA1_Channel7_IRQHandler - .thumb_set DMA1_Channel7_IRQHandler,Default_Handler - - .weak ADC1_2_IRQHandler - .thumb_set ADC1_2_IRQHandler,Default_Handler -#else - .weak DMA1_Stream0_IRQHandler - .thumb_set DMA1_Stream0_IRQHandler,Default_Handler - - .weak DMA1_Stream1_IRQHandler - .thumb_set DMA1_Stream1_IRQHandler,Default_Handler - - .weak DMA1_Stream2_IRQHandler - .thumb_set DMA1_Stream2_IRQHandler,Default_Handler - - .weak DMA1_Stream3_IRQHandler - .thumb_set DMA1_Stream3_IRQHandler,Default_Handler - - .weak DMA1_Stream4_IRQHandler - .thumb_set DMA1_Stream4_IRQHandler,Default_Handler - - .weak DMA1_Stream5_IRQHandler - .thumb_set DMA1_Stream5_IRQHandler,Default_Handler - - .weak DMA1_Stream6_IRQHandler - .thumb_set DMA1_Stream6_IRQHandler,Default_Handler - - .weak ADC_IRQHandler - .thumb_set ADC_IRQHandler,Default_Handler -#endif - - .weak CAN1_TX_IRQHandler - .thumb_set CAN1_TX_IRQHandler,Default_Handler - - .weak CAN1_RX0_IRQHandler - .thumb_set CAN1_RX0_IRQHandler,Default_Handler - - .weak CAN1_RX1_IRQHandler - .thumb_set CAN1_RX1_IRQHandler,Default_Handler - - .weak CAN1_SCE_IRQHandler - .thumb_set CAN1_SCE_IRQHandler,Default_Handler - - .weak EXTI9_5_IRQHandler - .thumb_set EXTI9_5_IRQHandler,Default_Handler - -#if defined(MCU_SERIES_L4) - .weak TIM1_BRK_TIM15_IRQHandler - .thumb_set TIM1_BRK_TIM15_IRQHandler,Default_Handler - - .weak TIM1_UP_TIM16_IRQHandler - .thumb_set TIM1_UP_TIM16_IRQHandler,Default_Handler - - .weak TIM1_TRG_COM_TIM17_IRQHandler - .thumb_set TIM1_TRG_COM_TIM17_IRQHandler,Default_Handler -#else - .weak TIM1_BRK_TIM9_IRQHandler - .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler - - .weak TIM1_UP_TIM10_IRQHandler - .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler - - .weak TIM1_TRG_COM_TIM11_IRQHandler - .thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler -#endif - - .weak TIM1_CC_IRQHandler - .thumb_set TIM1_CC_IRQHandler,Default_Handler - - .weak TIM2_IRQHandler - .thumb_set TIM2_IRQHandler,Default_Handler - - .weak TIM3_IRQHandler - .thumb_set TIM3_IRQHandler,Default_Handler - - .weak TIM4_IRQHandler - .thumb_set TIM4_IRQHandler,Default_Handler - - .weak I2C1_EV_IRQHandler - .thumb_set I2C1_EV_IRQHandler,Default_Handler - - .weak I2C1_ER_IRQHandler - .thumb_set I2C1_ER_IRQHandler,Default_Handler - - .weak I2C2_EV_IRQHandler - .thumb_set I2C2_EV_IRQHandler,Default_Handler - - .weak I2C2_ER_IRQHandler - .thumb_set I2C2_ER_IRQHandler,Default_Handler - - .weak SPI1_IRQHandler - .thumb_set SPI1_IRQHandler,Default_Handler - - .weak SPI2_IRQHandler - .thumb_set SPI2_IRQHandler,Default_Handler - - .weak USART1_IRQHandler - .thumb_set USART1_IRQHandler,Default_Handler - - .weak USART2_IRQHandler - .thumb_set USART2_IRQHandler,Default_Handler - - .weak USART3_IRQHandler - .thumb_set USART3_IRQHandler,Default_Handler - - .weak EXTI15_10_IRQHandler - .thumb_set EXTI15_10_IRQHandler,Default_Handler - - .weak RTC_Alarm_IRQHandler - .thumb_set RTC_Alarm_IRQHandler,Default_Handler - -#if defined(MCU_SERIES_L4) - .weak DFSDM3_IRQHandler - .thumb_set DFSDM3_IRQHandler,Default_Handler - - .weak TIM8_BRK_IRQHandler - .thumb_set TIM8_BRK_IRQHandler,Default_Handler - - .weak TIM8_UP_IRQHandler - .thumb_set TIM8_UP_IRQHandler,Default_Handler - - .weak TIM8_TRG_COM_IRQHandler - .thumb_set TIM8_TRG_COM_IRQHandler,Default_Handler -#else - .weak OTG_FS_WKUP_IRQHandler - .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler - - .weak TIM8_BRK_TIM12_IRQHandler - .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler - - .weak TIM8_UP_TIM13_IRQHandler - .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler - - .weak TIM8_TRG_COM_TIM14_IRQHandler - .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler -#endif - - .weak TIM8_CC_IRQHandler - .thumb_set TIM8_CC_IRQHandler,Default_Handler - -#if defined(MCU_SERIES_L4) - .weak ADC3_IRQHandler - .thumb_set ADC3_IRQHandler,Default_Handler -#else - .weak DMA1_Stream7_IRQHandler - .thumb_set DMA1_Stream7_IRQHandler,Default_Handler -#endif - -#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) - .weak FMC_IRQHandler - .thumb_set FMC_IRQHandler,Default_Handler - - .weak SDMMC1_IRQHandler - .thumb_set SDMMC1_IRQHandler,Default_Handler -#else - .weak FSMC_IRQHandler - .thumb_set FSMC_IRQHandler,Default_Handler - - .weak SDIO_IRQHandler - .thumb_set SDIO_IRQHandler,Default_Handler -#endif - - .weak TIM5_IRQHandler - .thumb_set TIM5_IRQHandler,Default_Handler - - .weak SPI3_IRQHandler - .thumb_set SPI3_IRQHandler,Default_Handler - - .weak UART4_IRQHandler - .thumb_set UART4_IRQHandler,Default_Handler - - .weak UART5_IRQHandler - .thumb_set UART5_IRQHandler,Default_Handler - - .weak TIM6_DAC_IRQHandler - .thumb_set TIM6_DAC_IRQHandler,Default_Handler - - .weak TIM7_IRQHandler - .thumb_set TIM7_IRQHandler,Default_Handler - -#if defined(MCU_SERIES_L4) - .weak DMA2_Channel1_IRQHandler - .thumb_set DMA2_Channel1_IRQHandler,Default_Handler - - .weak DMA2_Channel2_IRQHandler - .thumb_set DMA2_Channel2_IRQHandler,Default_Handler - - .weak DMA2_Channel3_IRQHandler - .thumb_set DMA2_Channel3_IRQHandler,Default_Handler - - .weak DMA2_Channel4_IRQHandler - .thumb_set DMA2_Channel4_IRQHandler,Default_Handler - - .weak DMA2_Channel5_IRQHandler - .thumb_set DMA2_Channel5_IRQHandler,Default_Handler - - .weak DFSDM0_IRQHandler - .thumb_set DFSDM0_IRQHandler,Default_Handler - - .weak DFSDM1_IRQHandler - .thumb_set DFSDM1_IRQHandler,Default_Handler - - .weak DFSDM2_IRQHandler - .thumb_set DFSDM2_IRQHandler,Default_Handler - - .weak COMP_IRQHandler - .thumb_set COMP_IRQHandler,Default_Handler - - .weak LPTIM1_IRQHandler - .thumb_set LPTIM1_IRQHandler,Default_Handler - - .weak LPTIM2_IRQHandler - .thumb_set LPTIM2_IRQHandler,Default_Handler -#else - .weak DMA2_Stream0_IRQHandler - .thumb_set DMA2_Stream0_IRQHandler,Default_Handler - - .weak DMA2_Stream1_IRQHandler - .thumb_set DMA2_Stream1_IRQHandler,Default_Handler - - .weak DMA2_Stream2_IRQHandler - .thumb_set DMA2_Stream2_IRQHandler,Default_Handler - - .weak DMA2_Stream3_IRQHandler - .thumb_set DMA2_Stream3_IRQHandler,Default_Handler - - .weak DMA2_Stream4_IRQHandler - .thumb_set DMA2_Stream4_IRQHandler,Default_Handler - - .weak ETH_IRQHandler - .thumb_set ETH_IRQHandler,Default_Handler - - .weak ETH_WKUP_IRQHandler - .thumb_set ETH_WKUP_IRQHandler,Default_Handler - - .weak CAN2_TX_IRQHandler - .thumb_set CAN2_TX_IRQHandler,Default_Handler - - .weak CAN2_RX0_IRQHandler - .thumb_set CAN2_RX0_IRQHandler,Default_Handler - - .weak CAN2_RX1_IRQHandler - .thumb_set CAN2_RX1_IRQHandler,Default_Handler - - .weak CAN2_SCE_IRQHandler - .thumb_set CAN2_SCE_IRQHandler,Default_Handler -#endif - - .weak OTG_FS_IRQHandler - .thumb_set OTG_FS_IRQHandler,Default_Handler - -#if defined(MCU_SERIES_L4) - .weak DMA2_Channel6_IRQHandler - .thumb_set DMA2_Channel6_IRQHandler,Default_Handler - - .weak DMA2_Channel7_IRQHandler - .thumb_set DMA2_Channel7_IRQHandler,Default_Handler - - .weak LPUART1_IRQHandler - .thumb_set LPUART1_IRQHandler,Default_Handler - - .weak QUADSPI_IRQHandler - .thumb_set QUADSPI_IRQHandler,Default_Handler -#else - .weak DMA2_Stream5_IRQHandler - .thumb_set DMA2_Stream5_IRQHandler,Default_Handler - - .weak DMA2_Stream6_IRQHandler - .thumb_set DMA2_Stream6_IRQHandler,Default_Handler - - .weak DMA2_Stream7_IRQHandler - .thumb_set DMA2_Stream7_IRQHandler,Default_Handler - - .weak USART6_IRQHandler - .thumb_set USART6_IRQHandler,Default_Handler -#endif - - .weak I2C3_EV_IRQHandler - .thumb_set I2C3_EV_IRQHandler,Default_Handler - - .weak I2C3_ER_IRQHandler - .thumb_set I2C3_ER_IRQHandler,Default_Handler - -#if defined(MCU_SERIES_L4) - .weak SAI1_IRQHandler - .thumb_set SAI1_IRQHandler,Default_Handler - - .weak SAI2_IRQHandler - .thumb_set SAI2_IRQHandler,Default_Handler - - .weak SWPMI1_IRQHandler - .thumb_set SWPMI1_IRQHandler,Default_Handler - - .weak TSC_IRQHandler - .thumb_set TSC_IRQHandler,Default_Handler - - .weak LCD_IRQHandler - .thumb_set LCD_IRQHandler,Default_Handler - - .weak RNG_IRQHandler - .thumb_set RNG_IRQHandler,Default_Handler -#else - .weak OTG_HS_EP1_OUT_IRQHandler - .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler - - .weak OTG_HS_EP1_IN_IRQHandler - .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler - - .weak OTG_HS_WKUP_IRQHandler - .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler - - .weak OTG_HS_IRQHandler - .thumb_set OTG_HS_IRQHandler,Default_Handler - - .weak DCMI_IRQHandler - .thumb_set DCMI_IRQHandler,Default_Handler - - .weak HASH_RNG_IRQHandler - .thumb_set HASH_RNG_IRQHandler,Default_Handler -#endif - - .weak FPU_IRQHandler - .thumb_set FPU_IRQHandler,Default_Handler -#if defined(MCU_SERIES_F7) - .weak UART7_IRQHandler - .thumb_set UART7_IRQHandler,Default_Handler - - .weak UART8_IRQHandler - .thumb_set UART8_IRQHandler,Default_Handler - - .weak SPI4_IRQHandler - .thumb_set SPI4_IRQHandler,Default_Handler - - .weak SPI5_IRQHandler - .thumb_set SPI5_IRQHandler,Default_Handler - - .weak SPI6_IRQHandler - .thumb_set SPI6_IRQHandler,Default_Handler - - .weak SAI1_IRQHandler - .thumb_set SAI1_IRQHandler,Default_Handler - - .weak DMA2D_IRQHandler - .thumb_set DMA2D_IRQHandler,Default_Handler - - .weak SAI2_IRQHandler - .thumb_set SAI2_IRQHandler,Default_Handler - - .weak QUADSPI_IRQHandler - .thumb_set QUADSPI_IRQHandler,Default_Handler - - .weak LPTIM1_IRQHandler - .thumb_set LPTIM1_IRQHandler,Default_Handler - - .weak CEC_IRQHandler - .thumb_set CEC_IRQHandler,Default_Handler - - .weak I2C4_EV_IRQHandler - .thumb_set I2C4_EV_IRQHandler,Default_Handler - - .weak I2C4_ER_IRQHandler - .thumb_set I2C4_ER_IRQHandler,Default_Handler - - .weak SPDIF_RX_IRQHandler - .thumb_set SPDIF_RX_IRQHandler,Default_Handler - - .weak DSIHOST_IRQHandler - .thumb_set DSIHOST_IRQHandler,Default_Handler - - .weak DFSDM1_FLT0_IRQHandler - .thumb_set DFSDM1_FLT0_IRQHandler,Default_Handler - - .weak DFSDM1_FLT1_IRQHandler - .thumb_set DFSDM1_FLT1_IRQHandler,Default_Handler - - .weak DFSDM1_FLT2_IRQHandler - .thumb_set DFSDM1_FLT2_IRQHandler,Default_Handler - - .weak DFSDM1_FLT3_IRQHandler - .thumb_set DFSDM1_FLT3_IRQHandler,Default_Handler - - .weak SDMMC2_IRQHandler - .thumb_set SDMMC2_IRQHandler,Default_Handler -#endif - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ From 993f4345c0fd57668984dd1248e84017c2352238 Mon Sep 17 00:00:00 2001 From: Tom Collins Date: Thu, 8 Mar 2018 15:55:01 -0800 Subject: [PATCH 435/828] stm32/usbd_conf.h: Add include of stdint.h to fix compilation issues. --- ports/stm32/usbd_conf.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm32/usbd_conf.h b/ports/stm32/usbd_conf.h index 5fa3c513d6..bf96b7b494 100644 --- a/ports/stm32/usbd_conf.h +++ b/ports/stm32/usbd_conf.h @@ -34,6 +34,7 @@ #define __USBD_CONF_H /* Includes ------------------------------------------------------------------*/ +#include #include #include #include From 9cef2b03a7a7bae2adb91e42320efa3e2af33a22 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 9 Mar 2018 16:14:58 +1100 Subject: [PATCH 436/828] docs/reference/repl.rst: Fix some minor errors in the REPL tutorial. --- docs/reference/repl.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/reference/repl.rst b/docs/reference/repl.rst index 7a683ca220..1eccb9a88a 100644 --- a/docs/reference/repl.rst +++ b/docs/reference/repl.rst @@ -19,7 +19,7 @@ If your cursor is all the way back at the beginning, pressing RETURN will then execute the code that you've entered. The following shows what you'd see after entering a for statement (the underscore shows where the cursor winds up): - >>> for i in range(3): + >>> for i in range(30): ... _ If you then enter an if statement, an additional level of indentation will be @@ -58,9 +58,10 @@ Auto-completion While typing a command at the REPL, if the line typed so far corresponds to the beginning of the name of something, then pressing TAB will show -possible things that could be entered. For example type ``m`` and press TAB -and it should expand to ``machine``. Enter a dot ``.`` and press TAB again. You -should see something like: +possible things that could be entered. For example, first import the machine +module by entering ``import machine`` and pressing RETURN. +Then type ``m`` and press TAB and it should expand to ``machine``. +Enter a dot ``.`` and press TAB again. You should see something like: >>> machine. __name__ info unique_id reset @@ -151,7 +152,7 @@ method by which you're connected to the MicroPython board (USB-serial, or Wifi). You can perform a soft reset from the REPL by pressing Ctrl-D, or from your python code by executing: :: - raise SystemExit + machine.soft_reset() For example, if you reset your MicroPython board, and you execute a dir() command, you'd see something like this: From ad2a6e538ca008d5e25bb03223ac4b948a340aff Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 9 Mar 2018 13:37:00 +0200 Subject: [PATCH 437/828] stm32/system_stm32: Fix CONFIG_RCC_CR_2ND value to use bitwise or. --- ports/stm32/system_stm32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c index bd25a149b4..77875f32c3 100644 --- a/ports/stm32/system_stm32.c +++ b/ports/stm32/system_stm32.c @@ -110,7 +110,7 @@ void __fatal_error(const char *msg); #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) #define CONFIG_RCC_CR_1ST (RCC_CR_HSION) -#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON || RCC_CR_CSSON || RCC_CR_PLLON) +#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON | RCC_CR_CSSON | RCC_CR_PLLON) #define CONFIG_RCC_PLLCFGR (0x24003010) #if defined(MCU_SERIES_F4) @@ -124,7 +124,7 @@ const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; #elif defined(MCU_SERIES_L4) #define CONFIG_RCC_CR_1ST (RCC_CR_MSION) -#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON || RCC_CR_CSSON || RCC_CR_HSION || RCC_CR_PLLON) +#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON | RCC_CR_CSSON | RCC_CR_HSION | RCC_CR_PLLON) #define CONFIG_RCC_PLLCFGR (0x00001000) /* * FIXME Do not know why I have to define these arrays here! they should be defined in the From 58ebeca6a9a172a35b9298a911d450722797c409 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 9 Mar 2018 17:25:58 +1100 Subject: [PATCH 438/828] drivers/bus: Pull out software SPI implementation to dedicated driver. This patch takes the software SPI implementation from extmod/machine_spi.c and moves it to a dedicated file in drivers/bus/softspi.c. This allows the SPI driver to be used independently of the uPy runtime, making it a more general component. --- drivers/bus/softspi.c | 105 +++++++++++++++++++++++++++++ drivers/bus/spi.h | 55 +++++++++++++++ extmod/machine_spi.c | 114 ++++++++------------------------ extmod/machine_spi.h | 10 +-- ports/esp32/Makefile | 1 + ports/esp32/mpconfigport.h | 4 +- ports/esp8266/Makefile | 1 + ports/esp8266/esp8266_common.ld | 1 + ports/stm32/Makefile | 1 + ports/stm32/mpconfigport.h | 4 +- ports/stm32/spibdev.c | 4 +- 11 files changed, 202 insertions(+), 98 deletions(-) create mode 100644 drivers/bus/softspi.c create mode 100644 drivers/bus/spi.h diff --git a/drivers/bus/softspi.c b/drivers/bus/softspi.c new file mode 100644 index 0000000000..bc12d89d3b --- /dev/null +++ b/drivers/bus/softspi.c @@ -0,0 +1,105 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "drivers/bus/spi.h" + +int mp_soft_spi_ioctl(void *self_in, uint32_t cmd) { + mp_soft_spi_obj_t *self = (mp_soft_spi_obj_t*)self_in; + + switch (cmd) { + case MP_SPI_IOCTL_INIT: + mp_hal_pin_write(self->sck, self->polarity); + mp_hal_pin_output(self->sck); + mp_hal_pin_output(self->mosi); + mp_hal_pin_input(self->miso); + break; + + case MP_SPI_IOCTL_DEINIT: + break; + } + + return 0; +} + +void mp_soft_spi_transfer(void *self_in, size_t len, const uint8_t *src, uint8_t *dest) { + mp_soft_spi_obj_t *self = (mp_soft_spi_obj_t*)self_in; + uint32_t delay_half = self->delay_half; + + // only MSB transfer is implemented + + // If a port defines MICROPY_HW_SOFTSPI_MIN_DELAY, and the configured + // delay_half is equal to this value, then the software SPI implementation + // will run as fast as possible, limited only by CPU speed and GPIO time. + #ifdef MICROPY_HW_SOFTSPI_MIN_DELAY + if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) { + for (size_t i = 0; i < len; ++i) { + uint8_t data_out = src[i]; + uint8_t data_in = 0; + for (int j = 0; j < 8; ++j, data_out <<= 1) { + mp_hal_pin_write(self->mosi, (data_out >> 7) & 1); + mp_hal_pin_write(self->sck, 1 - self->polarity); + data_in = (data_in << 1) | mp_hal_pin_read(self->miso); + mp_hal_pin_write(self->sck, self->polarity); + } + if (dest != NULL) { + dest[i] = data_in; + } + } + return; + } + #endif + + for (size_t i = 0; i < len; ++i) { + uint8_t data_out = src[i]; + uint8_t data_in = 0; + for (int j = 0; j < 8; ++j, data_out <<= 1) { + mp_hal_pin_write(self->mosi, (data_out >> 7) & 1); + if (self->phase == 0) { + mp_hal_delay_us_fast(delay_half); + mp_hal_pin_write(self->sck, 1 - self->polarity); + } else { + mp_hal_pin_write(self->sck, 1 - self->polarity); + mp_hal_delay_us_fast(delay_half); + } + data_in = (data_in << 1) | mp_hal_pin_read(self->miso); + if (self->phase == 0) { + mp_hal_delay_us_fast(delay_half); + mp_hal_pin_write(self->sck, self->polarity); + } else { + mp_hal_pin_write(self->sck, self->polarity); + mp_hal_delay_us_fast(delay_half); + } + } + if (dest != NULL) { + dest[i] = data_in; + } + } +} + +const mp_spi_proto_t mp_soft_spi_proto = { + .ioctl = mp_soft_spi_ioctl, + .transfer = mp_soft_spi_transfer, +}; diff --git a/drivers/bus/spi.h b/drivers/bus/spi.h new file mode 100644 index 0000000000..6d1b9c2f83 --- /dev/null +++ b/drivers/bus/spi.h @@ -0,0 +1,55 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_DRIVERS_BUS_SPI_H +#define MICROPY_INCLUDED_DRIVERS_BUS_SPI_H + +#include "py/mphal.h" + +enum { + MP_SPI_IOCTL_INIT, + MP_SPI_IOCTL_DEINIT, +}; + +typedef struct _mp_spi_proto_t { + int (*ioctl)(void *self, uint32_t cmd); + void (*transfer)(void *self, size_t len, const uint8_t *src, uint8_t *dest); +} mp_spi_proto_t; + +typedef struct _mp_soft_spi_obj_t { + uint32_t delay_half; // microsecond delay for half SCK period + uint8_t polarity; + uint8_t phase; + mp_hal_pin_obj_t sck; + mp_hal_pin_obj_t mosi; + mp_hal_pin_obj_t miso; +} mp_soft_spi_obj_t; + +extern const mp_spi_proto_t mp_soft_spi_proto; + +int mp_soft_spi_ioctl(void *self, uint32_t cmd); +void mp_soft_spi_transfer(void *self, size_t len, const uint8_t *src, uint8_t *dest); + +#endif // MICROPY_INCLUDED_DRIVERS_BUS_SPI_H diff --git a/extmod/machine_spi.c b/extmod/machine_spi.c index cfd94fcef7..f0c4896c2e 100644 --- a/extmod/machine_spi.c +++ b/extmod/machine_spi.c @@ -38,61 +38,6 @@ #define MICROPY_PY_MACHINE_SPI_LSB (1) #endif -void mp_machine_soft_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { - mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t*)self_in; - uint32_t delay_half = self->delay_half; - - // only MSB transfer is implemented - - // If a port defines MICROPY_PY_MACHINE_SPI_MIN_DELAY, and the configured - // delay_half is equal to this value, then the software SPI implementation - // will run as fast as possible, limited only by CPU speed and GPIO time. - #ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY - if (delay_half == MICROPY_PY_MACHINE_SPI_MIN_DELAY) { - for (size_t i = 0; i < len; ++i) { - uint8_t data_out = src[i]; - uint8_t data_in = 0; - for (int j = 0; j < 8; ++j, data_out <<= 1) { - mp_hal_pin_write(self->mosi, (data_out >> 7) & 1); - mp_hal_pin_write(self->sck, 1 - self->polarity); - data_in = (data_in << 1) | mp_hal_pin_read(self->miso); - mp_hal_pin_write(self->sck, self->polarity); - } - if (dest != NULL) { - dest[i] = data_in; - } - } - return; - } - #endif - - for (size_t i = 0; i < len; ++i) { - uint8_t data_out = src[i]; - uint8_t data_in = 0; - for (int j = 0; j < 8; ++j, data_out <<= 1) { - mp_hal_pin_write(self->mosi, (data_out >> 7) & 1); - if (self->phase == 0) { - mp_hal_delay_us_fast(delay_half); - mp_hal_pin_write(self->sck, 1 - self->polarity); - } else { - mp_hal_pin_write(self->sck, 1 - self->polarity); - mp_hal_delay_us_fast(delay_half); - } - data_in = (data_in << 1) | mp_hal_pin_read(self->miso); - if (self->phase == 0) { - mp_hal_delay_us_fast(delay_half); - mp_hal_pin_write(self->sck, self->polarity); - } else { - mp_hal_pin_write(self->sck, self->polarity); - mp_hal_delay_us_fast(delay_half); - } - } - if (dest != NULL) { - dest[i] = data_in; - } - } -} - /******************************************************************************/ // MicroPython bindings for generic machine.SPI @@ -199,9 +144,9 @@ MP_DEFINE_CONST_DICT(mp_machine_spi_locals_dict, machine_spi_locals_dict_table); // Implementation of soft SPI STATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) { - #ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY - if (delay_half == MICROPY_PY_MACHINE_SPI_MIN_DELAY) { - return MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE; + #ifdef MICROPY_HW_SOFTSPI_MIN_DELAY + if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) { + return MICROPY_HW_SOFTSPI_MAX_BAUDRATE; } else #endif { @@ -210,9 +155,9 @@ STATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) { } STATIC uint32_t baudrate_to_delay_half(uint32_t baudrate) { - #ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY - if (baudrate >= MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE) { - return MICROPY_PY_MACHINE_SPI_MIN_DELAY; + #ifdef MICROPY_HW_SOFTSPI_MIN_DELAY + if (baudrate >= MICROPY_HW_SOFTSPI_MAX_BAUDRATE) { + return MICROPY_HW_SOFTSPI_MIN_DELAY; } else #endif { @@ -229,8 +174,8 @@ STATIC void mp_machine_soft_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_machine_soft_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "SoftSPI(baudrate=%u, polarity=%u, phase=%u," " sck=" MP_HAL_PIN_FMT ", mosi=" MP_HAL_PIN_FMT ", miso=" MP_HAL_PIN_FMT ")", - baudrate_from_delay_half(self->delay_half), self->polarity, self->phase, - mp_hal_pin_name(self->sck), mp_hal_pin_name(self->mosi), mp_hal_pin_name(self->miso)); + baudrate_from_delay_half(self->spi.delay_half), self->spi.polarity, self->spi.phase, + mp_hal_pin_name(self->spi.sck), mp_hal_pin_name(self->spi.mosi), mp_hal_pin_name(self->spi.miso)); } STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { @@ -253,9 +198,9 @@ STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n self->base.type = &mp_machine_soft_spi_type; // set parameters - self->delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int); - self->polarity = args[ARG_polarity].u_int; - self->phase = args[ARG_phase].u_int; + self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int); + self->spi.polarity = args[ARG_polarity].u_int; + self->spi.phase = args[ARG_phase].u_int; if (args[ARG_bits].u_int != 8) { mp_raise_ValueError("bits must be 8"); } @@ -267,15 +212,12 @@ STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n || args[ARG_miso].u_obj == MP_OBJ_NULL) { mp_raise_ValueError("must specify all of sck/mosi/miso"); } - self->sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj); - self->mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj); - self->miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj); + self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj); + self->spi.mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj); + self->spi.miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj); - // configure pins - mp_hal_pin_write(self->sck, self->polarity); - mp_hal_pin_output(self->sck); - mp_hal_pin_output(self->mosi); - mp_hal_pin_input(self->miso); + // configure bus + mp_soft_spi_ioctl(&self->spi, MP_SPI_IOCTL_INIT); return MP_OBJ_FROM_PTR(self); } @@ -296,29 +238,31 @@ STATIC void mp_machine_soft_spi_init(mp_obj_base_t *self_in, size_t n_args, cons mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); if (args[ARG_baudrate].u_int != -1) { - self->delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int); + self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int); } if (args[ARG_polarity].u_int != -1) { - self->polarity = args[ARG_polarity].u_int; + self->spi.polarity = args[ARG_polarity].u_int; } if (args[ARG_phase].u_int != -1) { - self->phase = args[ARG_phase].u_int; + self->spi.phase = args[ARG_phase].u_int; } if (args[ARG_sck].u_obj != MP_OBJ_NULL) { - self->sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj); + self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj); } if (args[ARG_mosi].u_obj != MP_OBJ_NULL) { - self->mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj); + self->spi.mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj); } if (args[ARG_miso].u_obj != MP_OBJ_NULL) { - self->miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj); + self->spi.miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj); } - // configure pins - mp_hal_pin_write(self->sck, self->polarity); - mp_hal_pin_output(self->sck); - mp_hal_pin_output(self->mosi); - mp_hal_pin_input(self->miso); + // configure bus + mp_soft_spi_ioctl(&self->spi, MP_SPI_IOCTL_INIT); +} + +STATIC void mp_machine_soft_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { + mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t*)self_in; + mp_soft_spi_transfer(&self->spi, len, src, dest); } const mp_machine_spi_p_t mp_machine_soft_spi_p = { diff --git a/extmod/machine_spi.h b/extmod/machine_spi.h index 3ee1b241f0..db21e1cd31 100644 --- a/extmod/machine_spi.h +++ b/extmod/machine_spi.h @@ -28,6 +28,7 @@ #include "py/obj.h" #include "py/mphal.h" +#include "drivers/bus/spi.h" // SPI protocol typedef struct _mp_machine_spi_p_t { @@ -38,20 +39,13 @@ typedef struct _mp_machine_spi_p_t { typedef struct _mp_machine_soft_spi_obj_t { mp_obj_base_t base; - uint32_t delay_half; // microsecond delay for half SCK period - uint8_t polarity; - uint8_t phase; - mp_hal_pin_obj_t sck; - mp_hal_pin_obj_t mosi; - mp_hal_pin_obj_t miso; + mp_soft_spi_obj_t spi; } mp_machine_soft_spi_obj_t; extern const mp_machine_spi_p_t mp_machine_soft_spi_p; extern const mp_obj_type_t mp_machine_soft_spi_type; extern const mp_obj_dict_t mp_machine_spi_locals_dict; -void mp_machine_soft_spi_transfer(mp_obj_base_t *self, size_t len, const uint8_t *src, uint8_t *dest); - mp_obj_t mp_machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj); diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index eb0a3be249..d2d6192b5f 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -195,6 +195,7 @@ LIB_SRC_C += \ endif DRIVERS_SRC_C = $(addprefix drivers/,\ + bus/softspi.c \ dht/dht.c \ ) diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index bf027f1c5c..80594b1144 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -135,8 +135,8 @@ #define MICROPY_PY_MACHINE_SPI_MSB (0) #define MICROPY_PY_MACHINE_SPI_LSB (1) #define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hw_spi_make_new -#define MICROPY_PY_MACHINE_SPI_MIN_DELAY (0) -#define MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE (ets_get_cpu_frequency() * 1000000 / 200) // roughly +#define MICROPY_HW_SOFTSPI_MIN_DELAY (0) +#define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (ets_get_cpu_frequency() * 1000000 / 200) // roughly #define MICROPY_PY_USSL (1) #define MICROPY_SSL_MBEDTLS (1) #define MICROPY_PY_USSL_FINALISER (1) diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile index 9d6e502c78..716f18d6a1 100644 --- a/ports/esp8266/Makefile +++ b/ports/esp8266/Makefile @@ -130,6 +130,7 @@ LIB_SRC_C += \ endif DRIVERS_SRC_C = $(addprefix drivers/,\ + bus/softspi.c \ dht/dht.c \ ) diff --git a/ports/esp8266/esp8266_common.ld b/ports/esp8266/esp8266_common.ld index 08da02869a..6b7eba56a8 100644 --- a/ports/esp8266/esp8266_common.ld +++ b/ports/esp8266/esp8266_common.ld @@ -135,6 +135,7 @@ SECTIONS *lib/netutils/*.o*(.literal*, .text*) *lib/timeutils/*.o*(.literal*, .text*) *lib/utils/*.o*(.literal*, .text*) + *drivers/bus/*.o(.literal* .text*) build/main.o(.literal* .text*) *gccollect.o(.literal* .text*) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 112093f844..765c55a352 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -187,6 +187,7 @@ EXTMOD_SRC_C = $(addprefix extmod/,\ ) DRIVERS_SRC_C = $(addprefix drivers/,\ + bus/softspi.c \ bus/softqspi.c \ memory/spiflash.c \ dht/dht.c \ diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 35b59cbfd8..a0a67e95f9 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -140,8 +140,8 @@ #define MICROPY_PY_MACHINE_SPI_MSB (SPI_FIRSTBIT_MSB) #define MICROPY_PY_MACHINE_SPI_LSB (SPI_FIRSTBIT_LSB) #define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hard_spi_make_new -#define MICROPY_PY_MACHINE_SPI_MIN_DELAY (0) -#define MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE (HAL_RCC_GetSysClockFreq() / 48) +#define MICROPY_HW_SOFTSPI_MIN_DELAY (0) +#define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (HAL_RCC_GetSysClockFreq() / 48) #define MICROPY_PY_FRAMEBUF (1) #ifndef MICROPY_PY_USOCKET #define MICROPY_PY_USOCKET (1) diff --git a/ports/stm32/spibdev.c b/ports/stm32/spibdev.c index 3eadb995d6..846b29d1f0 100644 --- a/ports/stm32/spibdev.c +++ b/ports/stm32/spibdev.c @@ -42,12 +42,14 @@ static uint32_t flash_tick_counter_last_write; STATIC const mp_machine_soft_spi_obj_t spiflash_spi_bus = { .base = {&mp_machine_soft_spi_type}, - .delay_half = MICROPY_PY_MACHINE_SPI_MIN_DELAY, + .spi = { + .delay_half = MICROPY_HW_SOFTSPI_MIN_DELAY, .polarity = 0, .phase = 0, .sck = &MICROPY_HW_SPIFLASH_SCK, .mosi = &MICROPY_HW_SPIFLASH_MOSI, .miso = &MICROPY_HW_SPIFLASH_MISO, + } }; STATIC const mp_spiflash_config_t spiflash_config = { From a739b35a9618c2dd2d25c9ef4d076eeffddbb399 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 9 Mar 2018 17:32:28 +1100 Subject: [PATCH 439/828] drivers/memory/spiflash: Change to use low-level SPI object not uPy one. This patch alters the SPI-flash memory driver so that it uses the new low-level C SPI protocol (from drivers/bus/spi.h) instead of the uPy SPI protocol (from extmod/machine_spi.h). This allows the SPI-flash driver to be used independently from the uPy runtime. --- drivers/memory/spiflash.c | 2 +- drivers/memory/spiflash.h | 4 ++-- ports/stm32/spibdev.c | 9 +++------ 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c index ea0fef8052..ad451f2c5d 100644 --- a/drivers/memory/spiflash.c +++ b/drivers/memory/spiflash.c @@ -162,7 +162,7 @@ void mp_spiflash_init(mp_spiflash_t *self) { if (self->config->bus_kind == MP_SPIFLASH_BUS_SPI) { mp_hal_pin_write(self->config->bus.u_spi.cs, 1); mp_hal_pin_output(self->config->bus.u_spi.cs); - self->config->bus.u_spi.proto->init(self->config->bus.u_spi.data, 0, NULL, (mp_map_t*)&mp_const_empty_map); + self->config->bus.u_spi.proto->ioctl(self->config->bus.u_spi.data, MP_SPI_IOCTL_INIT); } else { self->config->bus.u_qspi.proto->ioctl(self->config->bus.u_qspi.data, MP_QSPI_IOCTL_INIT); } diff --git a/drivers/memory/spiflash.h b/drivers/memory/spiflash.h index 79ba5490b1..03bad5296a 100644 --- a/drivers/memory/spiflash.h +++ b/drivers/memory/spiflash.h @@ -26,8 +26,8 @@ #ifndef MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H #define MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H +#include "drivers/bus/spi.h" #include "drivers/bus/qspi.h" -#include "extmod/machine_spi.h" enum { MP_SPIFLASH_BUS_SPI, @@ -40,7 +40,7 @@ typedef struct _mp_spiflash_config_t { struct { mp_hal_pin_obj_t cs; void *data; - const mp_machine_spi_p_t *proto; + const mp_spi_proto_t *proto; } u_spi; struct { void *data; diff --git a/ports/stm32/spibdev.c b/ports/stm32/spibdev.c index 846b29d1f0..0e47a8189e 100644 --- a/ports/stm32/spibdev.c +++ b/ports/stm32/spibdev.c @@ -40,23 +40,20 @@ static uint32_t flash_tick_counter_last_write; // External SPI flash uses standard SPI interface -STATIC const mp_machine_soft_spi_obj_t spiflash_spi_bus = { - .base = {&mp_machine_soft_spi_type}, - .spi = { +STATIC const mp_soft_spi_obj_t soft_spi_bus = { .delay_half = MICROPY_HW_SOFTSPI_MIN_DELAY, .polarity = 0, .phase = 0, .sck = &MICROPY_HW_SPIFLASH_SCK, .mosi = &MICROPY_HW_SPIFLASH_MOSI, .miso = &MICROPY_HW_SPIFLASH_MISO, - } }; STATIC const mp_spiflash_config_t spiflash_config = { .bus_kind = MP_SPIFLASH_BUS_SPI, .bus.u_spi.cs = &MICROPY_HW_SPIFLASH_CS, - .bus.u_spi.data = (void*)&spiflash_spi_bus, - .bus.u_spi.proto = &mp_machine_soft_spi_p, + .bus.u_spi.data = (void*)&soft_spi_bus, + .bus.u_spi.proto = &mp_soft_spi_proto, }; #elif defined(MICROPY_HW_SPIFLASH_IO0) From 1e4caf0b1ec4dcdf2348e9e0a07a12c9f63f3176 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 9 Mar 2018 22:22:29 +1100 Subject: [PATCH 440/828] stm32/storage: Merge all misc block-dev funcs into a single ioctl func. It makes it cleaner, and simpler to support multiple different block devices. It also allows to easily extend a given block device with new ioctl operations. --- ports/stm32/flashbdev.c | 44 +++++++++++++++++++++++++-------------- ports/stm32/spibdev.c | 46 +++++++++++++++++++++++++---------------- ports/stm32/storage.c | 34 ++++++++++-------------------- ports/stm32/storage.h | 17 ++++++++------- 4 files changed, 77 insertions(+), 64 deletions(-) diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c index ec2e4f212d..fe7161275a 100644 --- a/ports/stm32/flashbdev.c +++ b/ports/stm32/flashbdev.c @@ -28,6 +28,7 @@ #include #include "py/obj.h" +#include "py/mperrno.h" #include "systick.h" #include "led.h" #include "flash.h" @@ -122,23 +123,34 @@ static uint32_t flash_cache_sector_start; static uint32_t flash_cache_sector_size; static uint32_t flash_tick_counter_last_write; -void flash_bdev_init(void) { - flash_flags = 0; - flash_cache_sector_id = 0; - flash_tick_counter_last_write = 0; -} +static void flash_bdev_irq_handler(void); -uint32_t flash_bdev_num_blocks(void) { - return FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS; -} +int32_t flash_bdev_ioctl(uint32_t op, uint32_t arg) { + (void)arg; + switch (op) { + case BDEV_IOCTL_INIT: + flash_flags = 0; + flash_cache_sector_id = 0; + flash_tick_counter_last_write = 0; + return 0; -void flash_bdev_flush(void) { - if (flash_flags & FLASH_FLAG_DIRTY) { - flash_flags |= FLASH_FLAG_FORCE_WRITE; - while (flash_flags & FLASH_FLAG_DIRTY) { - NVIC->STIR = FLASH_IRQn; - } + case BDEV_IOCTL_NUM_BLOCKS: + return FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS; + + case BDEV_IOCTL_IRQ_HANDLER: + flash_bdev_irq_handler(); + return 0; + + case BDEV_IOCTL_SYNC: + if (flash_flags & FLASH_FLAG_DIRTY) { + flash_flags |= FLASH_FLAG_FORCE_WRITE; + while (flash_flags & FLASH_FLAG_DIRTY) { + NVIC->STIR = FLASH_IRQn; + } + } + return 0; } + return -MP_EINVAL; } static uint8_t *flash_cache_get_addr_for_write(uint32_t flash_addr) { @@ -149,7 +161,7 @@ static uint8_t *flash_cache_get_addr_for_write(uint32_t flash_addr) { flash_sector_size = FLASH_SECTOR_SIZE_MAX; } if (flash_cache_sector_id != flash_sector_id) { - flash_bdev_flush(); + flash_bdev_ioctl(BDEV_IOCTL_SYNC, 0); memcpy((void*)CACHE_MEM_START_ADDR, (const void*)flash_sector_start, flash_sector_size); flash_cache_sector_id = flash_sector_id; flash_cache_sector_start = flash_sector_start; @@ -186,7 +198,7 @@ static uint32_t convert_block_to_flash_addr(uint32_t block) { return -1; } -void flash_bdev_irq_handler(void) { +static void flash_bdev_irq_handler(void) { if (!(flash_flags & FLASH_FLAG_DIRTY)) { return; } diff --git a/ports/stm32/spibdev.c b/ports/stm32/spibdev.c index 0e47a8189e..88f2cf51b7 100644 --- a/ports/stm32/spibdev.c +++ b/ports/stm32/spibdev.c @@ -25,6 +25,7 @@ */ #include "py/obj.h" +#include "py/mperrno.h" #include "systick.h" #include "led.h" #include "storage.h" @@ -81,27 +82,36 @@ STATIC const mp_spiflash_config_t spiflash_config = { STATIC mp_spiflash_t spiflash; -void spi_bdev_init(void) { - spiflash.config = &spiflash_config; - mp_spiflash_init(&spiflash); - flash_tick_counter_last_write = 0; -} +int32_t spi_bdev_ioctl(uint32_t op, uint32_t arg) { + (void)arg; + switch (op) { + case BDEV_IOCTL_INIT: + spiflash.config = &spiflash_config; + mp_spiflash_init(&spiflash); + flash_tick_counter_last_write = 0; + return 0; -void spi_bdev_irq_handler(void) { - if ((spiflash.flags & 1) && sys_tick_has_passed(flash_tick_counter_last_write, 1000)) { - mp_spiflash_flush(&spiflash); - led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off - } -} + case BDEV_IOCTL_NUM_BLOCKS: + return MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE; -void spi_bdev_flush(void) { - if (spiflash.flags & 1) { - // we must disable USB irqs to prevent MSC contention with SPI flash - uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - mp_spiflash_flush(&spiflash); - led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off - restore_irq_pri(basepri); + case BDEV_IOCTL_IRQ_HANDLER: + if ((spiflash.flags & 1) && sys_tick_has_passed(flash_tick_counter_last_write, 1000)) { + mp_spiflash_flush(&spiflash); + led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off + } + return 0; + + case BDEV_IOCTL_SYNC: + if (spiflash.flags & 1) { + // we must disable USB irqs to prevent MSC contention with SPI flash + uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); + mp_spiflash_flush(&spiflash); + led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off + restore_irq_pri(basepri); + } + return 0; } + return -MP_EINVAL; } int spi_bdev_readblocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index 46bd4fdc76..4e32fa3cc4 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -37,20 +37,14 @@ #if defined(MICROPY_HW_SPIFLASH_SIZE_BITS) // Use external SPI flash as the storage medium -#define BDEV_NUM_BLOCKS (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) -#define BDEV_INIT spi_bdev_init -#define BDEV_IRQ_HANDLER spi_bdev_irq_handler -#define BDEV_FLUSH spi_bdev_flush +#define BDEV_IOCTL spi_bdev_ioctl #define BDEV_READBLOCKS spi_bdev_readblocks #define BDEV_WRITEBLOCKS spi_bdev_writeblocks #else // Use internal flash as the storage medium -#define BDEV_NUM_BLOCKS flash_bdev_num_blocks() -#define BDEV_INIT flash_bdev_init -#define BDEV_IRQ_HANDLER flash_bdev_irq_handler -#define BDEV_FLUSH flash_bdev_flush +#define BDEV_IOCTL flash_bdev_ioctl #define BDEV_READBLOCK flash_bdev_readblock #define BDEV_WRITEBLOCK flash_bdev_writeblock @@ -64,15 +58,13 @@ void storage_init(void) { if (!storage_is_initialised) { storage_is_initialised = true; - BDEV_INIT(); + BDEV_IOCTL(BDEV_IOCTL_INIT, 0); - #if defined(BDEV_IRQ_HANDLER) // Enable the flash IRQ, which is used to also call our storage IRQ handler // It needs to go at a higher priority than all those components that rely on // the flash storage (eg higher than USB MSC). HAL_NVIC_SetPriority(FLASH_IRQn, IRQ_PRI_FLASH, IRQ_SUBPRI_FLASH); HAL_NVIC_EnableIRQ(FLASH_IRQn); - #endif } } @@ -81,19 +73,15 @@ uint32_t storage_get_block_size(void) { } uint32_t storage_get_block_count(void) { - return FLASH_PART1_START_BLOCK + BDEV_NUM_BLOCKS; + return FLASH_PART1_START_BLOCK + BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0); } void storage_irq_handler(void) { - #if defined(BDEV_IRQ_HANDLER) - BDEV_IRQ_HANDLER(); - #endif + BDEV_IOCTL(BDEV_IOCTL_IRQ_HANDLER, 0); } void storage_flush(void) { - #if defined(BDEV_FLUSH) - BDEV_FLUSH(); - #endif + BDEV_IOCTL(BDEV_IOCTL_SYNC, 0); } static void build_partition(uint8_t *buf, int boot, int type, uint32_t start_block, uint32_t num_blocks) { @@ -141,7 +129,7 @@ bool storage_read_block(uint8_t *dest, uint32_t block) { dest[i] = 0; } - build_partition(dest + 446, 0, 0x01 /* FAT12 */, FLASH_PART1_START_BLOCK, BDEV_NUM_BLOCKS); + build_partition(dest + 446, 0, 0x01 /* FAT12 */, FLASH_PART1_START_BLOCK, BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)); build_partition(dest + 462, 0, 0, 0, 0); build_partition(dest + 478, 0, 0, 0, 0); build_partition(dest + 494, 0, 0, 0, 0); @@ -152,7 +140,7 @@ bool storage_read_block(uint8_t *dest, uint32_t block) { return true; #if defined(BDEV_READBLOCK) - } else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + BDEV_NUM_BLOCKS) { + } else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { return BDEV_READBLOCK(dest, block - FLASH_PART1_START_BLOCK); #endif } else { @@ -166,7 +154,7 @@ bool storage_write_block(const uint8_t *src, uint32_t block) { // can't write MBR, but pretend we did return true; #if defined(BDEV_WRITEBLOCK) - } else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + BDEV_NUM_BLOCKS) { + } else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { return BDEV_WRITEBLOCK(src, block - FLASH_PART1_START_BLOCK); #endif } else { @@ -176,7 +164,7 @@ bool storage_write_block(const uint8_t *src, uint32_t block) { mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { #if defined(BDEV_READBLOCKS) - if (FLASH_PART1_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART1_START_BLOCK + BDEV_NUM_BLOCKS) { + if (FLASH_PART1_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART1_START_BLOCK + BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { return BDEV_READBLOCKS(dest, block_num - FLASH_PART1_START_BLOCK, num_blocks); } #endif @@ -191,7 +179,7 @@ mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_bl mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { #if defined(BDEV_WRITEBLOCKS) - if (FLASH_PART1_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART1_START_BLOCK + BDEV_NUM_BLOCKS) { + if (FLASH_PART1_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART1_START_BLOCK + BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { return BDEV_WRITEBLOCKS(src, block_num - FLASH_PART1_START_BLOCK, num_blocks); } #endif diff --git a/ports/stm32/storage.h b/ports/stm32/storage.h index 8b3cedb127..a3cdd84ebf 100644 --- a/ports/stm32/storage.h +++ b/ports/stm32/storage.h @@ -31,6 +31,14 @@ #define STORAGE_SYSTICK_MASK (0x1ff) // 512ms #define STORAGE_IDLE_TICK(tick) (((tick) & STORAGE_SYSTICK_MASK) == 2) +// Try to match Python-level VFS block protocol where possible for these constants +enum { + BDEV_IOCTL_INIT = 1, + BDEV_IOCTL_SYNC = 3, + BDEV_IOCTL_NUM_BLOCKS = 4, + BDEV_IOCTL_IRQ_HANDLER = 6, +}; + void storage_init(void); uint32_t storage_get_block_size(void); uint32_t storage_get_block_count(void); @@ -43,16 +51,11 @@ bool storage_write_block(const uint8_t *src, uint32_t block); mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks); mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks); -uint32_t flash_bdev_num_blocks(void); -void flash_bdev_init(void); -void flash_bdev_irq_handler(void); -void flash_bdev_flush(void); +int32_t flash_bdev_ioctl(uint32_t op, uint32_t arg); bool flash_bdev_readblock(uint8_t *dest, uint32_t block); bool flash_bdev_writeblock(const uint8_t *src, uint32_t block); -void spi_bdev_init(void); -void spi_bdev_irq_handler(void); -void spi_bdev_flush(void); +int32_t spi_bdev_ioctl(uint32_t op, uint32_t arg); int spi_bdev_readblocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks); int spi_bdev_writeblocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks); From 1803e8ef221c7714e4f663c777be2f8733721f3d Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 10 Mar 2018 00:22:38 +1100 Subject: [PATCH 441/828] stm32/storage: Make spi_bdev interface take a data pointer as first arg. This allows a board to have multiple instances of the SPI block device. --- ports/stm32/spibdev.c | 37 ++++++++++++++++--------------------- ports/stm32/storage.c | 11 ++++++++--- ports/stm32/storage.h | 15 ++++++++++++--- 3 files changed, 36 insertions(+), 27 deletions(-) diff --git a/ports/stm32/spibdev.c b/ports/stm32/spibdev.c index 88f2cf51b7..74b400a8fc 100644 --- a/ports/stm32/spibdev.c +++ b/ports/stm32/spibdev.c @@ -35,8 +35,6 @@ #include "drivers/memory/spiflash.h" #include "genhdr/pins.h" -static uint32_t flash_tick_counter_last_write; - #if defined(MICROPY_HW_SPIFLASH_MOSI) // External SPI flash uses standard SPI interface @@ -50,7 +48,7 @@ STATIC const mp_soft_spi_obj_t soft_spi_bus = { .miso = &MICROPY_HW_SPIFLASH_MISO, }; -STATIC const mp_spiflash_config_t spiflash_config = { +const mp_spiflash_config_t spiflash_config = { .bus_kind = MP_SPIFLASH_BUS_SPI, .bus.u_spi.cs = &MICROPY_HW_SPIFLASH_CS, .bus.u_spi.data = (void*)&soft_spi_bus, @@ -72,7 +70,7 @@ STATIC const mp_soft_qspi_obj_t soft_qspi_bus = { .io3 = &MICROPY_HW_SPIFLASH_IO3, }; -STATIC const mp_spiflash_config_t spiflash_config = { +const mp_spiflash_config_t spiflash_config = { .bus_kind = MP_SPIFLASH_BUS_QSPI, .bus.u_qspi.data = (void*)&soft_qspi_bus, .bus.u_qspi.proto = &mp_soft_qspi_proto, @@ -80,32 +78,29 @@ STATIC const mp_spiflash_config_t spiflash_config = { #endif -STATIC mp_spiflash_t spiflash; - -int32_t spi_bdev_ioctl(uint32_t op, uint32_t arg) { - (void)arg; +int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) { switch (op) { case BDEV_IOCTL_INIT: - spiflash.config = &spiflash_config; - mp_spiflash_init(&spiflash); - flash_tick_counter_last_write = 0; + bdev->spiflash.config = (const mp_spiflash_config_t*)arg; + mp_spiflash_init(&bdev->spiflash); + bdev->flash_tick_counter_last_write = 0; return 0; case BDEV_IOCTL_NUM_BLOCKS: return MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE; case BDEV_IOCTL_IRQ_HANDLER: - if ((spiflash.flags & 1) && sys_tick_has_passed(flash_tick_counter_last_write, 1000)) { - mp_spiflash_flush(&spiflash); + if ((bdev->spiflash.flags & 1) && sys_tick_has_passed(bdev->flash_tick_counter_last_write, 1000)) { + mp_spiflash_flush(&bdev->spiflash); led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off } return 0; case BDEV_IOCTL_SYNC: - if (spiflash.flags & 1) { + if (bdev->spiflash.flags & 1) { // we must disable USB irqs to prevent MSC contention with SPI flash uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - mp_spiflash_flush(&spiflash); + mp_spiflash_flush(&bdev->spiflash); led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off restore_irq_pri(basepri); } @@ -114,22 +109,22 @@ int32_t spi_bdev_ioctl(uint32_t op, uint32_t arg) { return -MP_EINVAL; } -int spi_bdev_readblocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { +int spi_bdev_readblocks(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { // we must disable USB irqs to prevent MSC contention with SPI flash uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - mp_spiflash_read(&spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, dest); + mp_spiflash_read(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, dest); restore_irq_pri(basepri); return 0; } -int spi_bdev_writeblocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { +int spi_bdev_writeblocks(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { // we must disable USB irqs to prevent MSC contention with SPI flash uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - int ret = mp_spiflash_write(&spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, src); - if (spiflash.flags & 1) { + int ret = mp_spiflash_write(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, src); + if (bdev->spiflash.flags & 1) { led_state(PYB_LED_RED, 1); // indicate a dirty cache with LED on - flash_tick_counter_last_write = HAL_GetTick(); + bdev->flash_tick_counter_last_write = HAL_GetTick(); } restore_irq_pri(basepri); diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index 4e32fa3cc4..0f565508bd 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -37,9 +37,14 @@ #if defined(MICROPY_HW_SPIFLASH_SIZE_BITS) // Use external SPI flash as the storage medium -#define BDEV_IOCTL spi_bdev_ioctl -#define BDEV_READBLOCKS spi_bdev_readblocks -#define BDEV_WRITEBLOCKS spi_bdev_writeblocks +STATIC spi_bdev_t spi_bdev; +#define BDEV_IOCTL(op, arg) ( \ + (op) == BDEV_IOCTL_NUM_BLOCKS ? (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) : \ + (op) == BDEV_IOCTL_INIT ? spi_bdev_ioctl(&spi_bdev, (op), (uint32_t)&spiflash_config) : \ + spi_bdev_ioctl(&spi_bdev, (op), (arg)) \ +) +#define BDEV_READBLOCKS(dest, bl, n) spi_bdev_readblocks(&spi_bdev, (dest), (bl), (n)) +#define BDEV_WRITEBLOCKS(src, bl, n) spi_bdev_writeblocks(&spi_bdev, (src), (bl), (n)) #else diff --git a/ports/stm32/storage.h b/ports/stm32/storage.h index a3cdd84ebf..c9514b8bc9 100644 --- a/ports/stm32/storage.h +++ b/ports/stm32/storage.h @@ -26,6 +26,8 @@ #ifndef MICROPY_INCLUDED_STM32_STORAGE_H #define MICROPY_INCLUDED_STM32_STORAGE_H +#include "drivers/memory/spiflash.h" + #define FLASH_BLOCK_SIZE (512) #define STORAGE_SYSTICK_MASK (0x1ff) // 512ms @@ -55,9 +57,16 @@ int32_t flash_bdev_ioctl(uint32_t op, uint32_t arg); bool flash_bdev_readblock(uint8_t *dest, uint32_t block); bool flash_bdev_writeblock(const uint8_t *src, uint32_t block); -int32_t spi_bdev_ioctl(uint32_t op, uint32_t arg); -int spi_bdev_readblocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks); -int spi_bdev_writeblocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks); +typedef struct _spi_bdev_t { + mp_spiflash_t spiflash; + uint32_t flash_tick_counter_last_write; +} spi_bdev_t; + +extern const mp_spiflash_config_t spiflash_config; + +int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg); +int spi_bdev_readblocks(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t num_blocks); +int spi_bdev_writeblocks(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_num, uint32_t num_blocks); extern const struct _mp_obj_type_t pyb_flash_type; From d1c4bd69dfa19b10b09f193d6a6c6a2f7548614c Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 10 Mar 2018 00:36:22 +1100 Subject: [PATCH 442/828] stm32/storage: Remove all SPI-flash bdev cfg, to be provided per board. If a board wants to use SPI flash for storage then it must now provide the configuration itself, using the MICROPY_HW_BDEV_xxx macros. --- ports/stm32/spibdev.c | 53 ------------------------------------------ ports/stm32/storage.c | 54 +++++++++++++++++-------------------------- ports/stm32/storage.h | 2 -- 3 files changed, 21 insertions(+), 88 deletions(-) diff --git a/ports/stm32/spibdev.c b/ports/stm32/spibdev.c index 74b400a8fc..007a96a6ca 100644 --- a/ports/stm32/spibdev.c +++ b/ports/stm32/spibdev.c @@ -30,54 +30,6 @@ #include "led.h" #include "storage.h" -#if defined(MICROPY_HW_SPIFLASH_SIZE_BITS) - -#include "drivers/memory/spiflash.h" -#include "genhdr/pins.h" - -#if defined(MICROPY_HW_SPIFLASH_MOSI) - -// External SPI flash uses standard SPI interface - -STATIC const mp_soft_spi_obj_t soft_spi_bus = { - .delay_half = MICROPY_HW_SOFTSPI_MIN_DELAY, - .polarity = 0, - .phase = 0, - .sck = &MICROPY_HW_SPIFLASH_SCK, - .mosi = &MICROPY_HW_SPIFLASH_MOSI, - .miso = &MICROPY_HW_SPIFLASH_MISO, -}; - -const mp_spiflash_config_t spiflash_config = { - .bus_kind = MP_SPIFLASH_BUS_SPI, - .bus.u_spi.cs = &MICROPY_HW_SPIFLASH_CS, - .bus.u_spi.data = (void*)&soft_spi_bus, - .bus.u_spi.proto = &mp_soft_spi_proto, -}; - -#elif defined(MICROPY_HW_SPIFLASH_IO0) - -// External SPI flash uses quad SPI interface - -#include "drivers/bus/qspi.h" - -STATIC const mp_soft_qspi_obj_t soft_qspi_bus = { - .cs = &MICROPY_HW_SPIFLASH_CS, - .clk = &MICROPY_HW_SPIFLASH_SCK, - .io0 = &MICROPY_HW_SPIFLASH_IO0, - .io1 = &MICROPY_HW_SPIFLASH_IO1, - .io2 = &MICROPY_HW_SPIFLASH_IO2, - .io3 = &MICROPY_HW_SPIFLASH_IO3, -}; - -const mp_spiflash_config_t spiflash_config = { - .bus_kind = MP_SPIFLASH_BUS_QSPI, - .bus.u_qspi.data = (void*)&soft_qspi_bus, - .bus.u_qspi.proto = &mp_soft_qspi_proto, -}; - -#endif - int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) { switch (op) { case BDEV_IOCTL_INIT: @@ -86,9 +38,6 @@ int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) { bdev->flash_tick_counter_last_write = 0; return 0; - case BDEV_IOCTL_NUM_BLOCKS: - return MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE; - case BDEV_IOCTL_IRQ_HANDLER: if ((bdev->spiflash.flags & 1) && sys_tick_has_passed(bdev->flash_tick_counter_last_write, 1000)) { mp_spiflash_flush(&bdev->spiflash); @@ -130,5 +79,3 @@ int spi_bdev_writeblocks(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_nu return ret; } - -#endif // defined(MICROPY_HW_SPIFLASH_SIZE_BITS) diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index 0f565508bd..ef583af155 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -34,24 +34,12 @@ #include "storage.h" #include "irq.h" -#if defined(MICROPY_HW_SPIFLASH_SIZE_BITS) - -// Use external SPI flash as the storage medium -STATIC spi_bdev_t spi_bdev; -#define BDEV_IOCTL(op, arg) ( \ - (op) == BDEV_IOCTL_NUM_BLOCKS ? (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) : \ - (op) == BDEV_IOCTL_INIT ? spi_bdev_ioctl(&spi_bdev, (op), (uint32_t)&spiflash_config) : \ - spi_bdev_ioctl(&spi_bdev, (op), (arg)) \ -) -#define BDEV_READBLOCKS(dest, bl, n) spi_bdev_readblocks(&spi_bdev, (dest), (bl), (n)) -#define BDEV_WRITEBLOCKS(src, bl, n) spi_bdev_writeblocks(&spi_bdev, (src), (bl), (n)) - -#else +#if !defined(MICROPY_HW_SPIFLASH_SIZE_BITS) // Use internal flash as the storage medium -#define BDEV_IOCTL flash_bdev_ioctl -#define BDEV_READBLOCK flash_bdev_readblock -#define BDEV_WRITEBLOCK flash_bdev_writeblock +#define MICROPY_HW_BDEV_IOCTL flash_bdev_ioctl +#define MICROPY_HW_BDEV_READBLOCK flash_bdev_readblock +#define MICROPY_HW_BDEV_WRITEBLOCK flash_bdev_writeblock #endif @@ -63,7 +51,7 @@ void storage_init(void) { if (!storage_is_initialised) { storage_is_initialised = true; - BDEV_IOCTL(BDEV_IOCTL_INIT, 0); + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_INIT, 0); // Enable the flash IRQ, which is used to also call our storage IRQ handler // It needs to go at a higher priority than all those components that rely on @@ -78,15 +66,15 @@ uint32_t storage_get_block_size(void) { } uint32_t storage_get_block_count(void) { - return FLASH_PART1_START_BLOCK + BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0); + return FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0); } void storage_irq_handler(void) { - BDEV_IOCTL(BDEV_IOCTL_IRQ_HANDLER, 0); + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_IRQ_HANDLER, 0); } void storage_flush(void) { - BDEV_IOCTL(BDEV_IOCTL_SYNC, 0); + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_SYNC, 0); } static void build_partition(uint8_t *buf, int boot, int type, uint32_t start_block, uint32_t num_blocks) { @@ -134,7 +122,7 @@ bool storage_read_block(uint8_t *dest, uint32_t block) { dest[i] = 0; } - build_partition(dest + 446, 0, 0x01 /* FAT12 */, FLASH_PART1_START_BLOCK, BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)); + build_partition(dest + 446, 0, 0x01 /* FAT12 */, FLASH_PART1_START_BLOCK, MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)); build_partition(dest + 462, 0, 0, 0, 0); build_partition(dest + 478, 0, 0, 0, 0); build_partition(dest + 494, 0, 0, 0, 0); @@ -144,9 +132,9 @@ bool storage_read_block(uint8_t *dest, uint32_t block) { return true; - #if defined(BDEV_READBLOCK) - } else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { - return BDEV_READBLOCK(dest, block - FLASH_PART1_START_BLOCK); + #if defined(MICROPY_HW_BDEV_READBLOCK) + } else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { + return MICROPY_HW_BDEV_READBLOCK(dest, block - FLASH_PART1_START_BLOCK); #endif } else { return false; @@ -158,9 +146,9 @@ bool storage_write_block(const uint8_t *src, uint32_t block) { if (block == 0) { // can't write MBR, but pretend we did return true; - #if defined(BDEV_WRITEBLOCK) - } else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { - return BDEV_WRITEBLOCK(src, block - FLASH_PART1_START_BLOCK); + #if defined(MICROPY_HW_BDEV_WRITEBLOCK) + } else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { + return MICROPY_HW_BDEV_WRITEBLOCK(src, block - FLASH_PART1_START_BLOCK); #endif } else { return false; @@ -168,9 +156,9 @@ bool storage_write_block(const uint8_t *src, uint32_t block) { } mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { - #if defined(BDEV_READBLOCKS) - if (FLASH_PART1_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART1_START_BLOCK + BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { - return BDEV_READBLOCKS(dest, block_num - FLASH_PART1_START_BLOCK, num_blocks); + #if defined(MICROPY_HW_BDEV_READBLOCKS) + if (FLASH_PART1_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { + return MICROPY_HW_BDEV_READBLOCKS(dest, block_num - FLASH_PART1_START_BLOCK, num_blocks); } #endif @@ -183,9 +171,9 @@ mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_bl } mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { - #if defined(BDEV_WRITEBLOCKS) - if (FLASH_PART1_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART1_START_BLOCK + BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { - return BDEV_WRITEBLOCKS(src, block_num - FLASH_PART1_START_BLOCK, num_blocks); + #if defined(MICROPY_HW_BDEV_WRITEBLOCKS) + if (FLASH_PART1_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { + return MICROPY_HW_BDEV_WRITEBLOCKS(src, block_num - FLASH_PART1_START_BLOCK, num_blocks); } #endif diff --git a/ports/stm32/storage.h b/ports/stm32/storage.h index c9514b8bc9..7250b6dbf9 100644 --- a/ports/stm32/storage.h +++ b/ports/stm32/storage.h @@ -62,8 +62,6 @@ typedef struct _spi_bdev_t { uint32_t flash_tick_counter_last_write; } spi_bdev_t; -extern const mp_spiflash_config_t spiflash_config; - int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg); int spi_bdev_readblocks(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t num_blocks); int spi_bdev_writeblocks(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_num, uint32_t num_blocks); From 626d6c9756df3f089b9f62d15f343cdf080c7f80 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 10 Mar 2018 00:50:27 +1100 Subject: [PATCH 443/828] stm32/storage: Introduce MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE cfg. This config variable controls whether to support storage on the internal flash of the MCU. It is enabled by default and should be explicitly disabled by boards that don't want internal flash storage. --- ports/stm32/flashbdev.c | 4 ++-- ports/stm32/mpconfigboard_common.h | 12 ++++++++++++ ports/stm32/storage.c | 9 --------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c index fe7161275a..64faf0eacd 100644 --- a/ports/stm32/flashbdev.c +++ b/ports/stm32/flashbdev.c @@ -34,7 +34,7 @@ #include "flash.h" #include "storage.h" -#if !defined(MICROPY_HW_SPIFLASH_SIZE_BITS) +#if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE // Here we try to automatically configure the location and size of the flash // pages to use for the internal storage. We also configure the location of the @@ -265,4 +265,4 @@ bool flash_bdev_writeblock(const uint8_t *src, uint32_t block) { return true; } -#endif // !defined(MICROPY_HW_SPIFLASH_SIZE_BITS) +#endif // MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 0c57976fb9..b876d5884a 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -32,6 +32,11 @@ /*****************************************************************************/ // Feature settings with defaults +// Whether to enable storage on the internal flash of the MCU +#ifndef MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE +#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (1) +#endif + // Whether to enable the RTC, exposed as pyb.RTC #ifndef MICROPY_HW_ENABLE_RTC #define MICROPY_HW_ENABLE_RTC (0) @@ -136,6 +141,13 @@ #error Unsupported MCU series #endif +#if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE +// Provide block device macros if internal flash storage is enabled +#define MICROPY_HW_BDEV_IOCTL flash_bdev_ioctl +#define MICROPY_HW_BDEV_READBLOCK flash_bdev_readblock +#define MICROPY_HW_BDEV_WRITEBLOCK flash_bdev_writeblock +#endif + // Enable hardware I2C if there are any peripherals defined #if defined(MICROPY_HW_I2C1_SCL) || defined(MICROPY_HW_I2C2_SCL) \ || defined(MICROPY_HW_I2C3_SCL) || defined(MICROPY_HW_I2C4_SCL) diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index ef583af155..4cf2898b32 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -34,15 +34,6 @@ #include "storage.h" #include "irq.h" -#if !defined(MICROPY_HW_SPIFLASH_SIZE_BITS) - -// Use internal flash as the storage medium -#define MICROPY_HW_BDEV_IOCTL flash_bdev_ioctl -#define MICROPY_HW_BDEV_READBLOCK flash_bdev_readblock -#define MICROPY_HW_BDEV_WRITEBLOCK flash_bdev_writeblock - -#endif - #define FLASH_PART1_START_BLOCK (0x100) static bool storage_is_initialised = false; From bb3359f357b7e73bb5cd76c4a267ea6f2fd90c7a Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 10 Mar 2018 00:55:06 +1100 Subject: [PATCH 444/828] stm32/boards/STM32L476DISC: Provide SPI-flash bdev config. This board shows how to configure external SPI flash as the main storage medium. It uses software SPI. --- ports/stm32/boards/STM32L476DISC/bdev.c | 22 +++++++++++++++++++ .../boards/STM32L476DISC/mpconfigboard.h | 12 ++++++++++ 2 files changed, 34 insertions(+) create mode 100644 ports/stm32/boards/STM32L476DISC/bdev.c diff --git a/ports/stm32/boards/STM32L476DISC/bdev.c b/ports/stm32/boards/STM32L476DISC/bdev.c new file mode 100644 index 0000000000..50a02498ac --- /dev/null +++ b/ports/stm32/boards/STM32L476DISC/bdev.c @@ -0,0 +1,22 @@ +#include "storage.h" +#include "genhdr/pins.h" + +// External SPI flash uses standard SPI interface + +const mp_soft_spi_obj_t soft_spi_bus = { + .delay_half = MICROPY_HW_SOFTSPI_MIN_DELAY, + .polarity = 0, + .phase = 0, + .sck = &MICROPY_HW_SPIFLASH_SCK, + .mosi = &MICROPY_HW_SPIFLASH_MOSI, + .miso = &MICROPY_HW_SPIFLASH_MISO, +}; + +const mp_spiflash_config_t spiflash_config = { + .bus_kind = MP_SPIFLASH_BUS_SPI, + .bus.u_spi.cs = &MICROPY_HW_SPIFLASH_CS, + .bus.u_spi.data = (void*)&soft_spi_bus, + .bus.u_spi.proto = &mp_soft_spi_proto, +}; + +spi_bdev_t spi_bdev; diff --git a/ports/stm32/boards/STM32L476DISC/mpconfigboard.h b/ports/stm32/boards/STM32L476DISC/mpconfigboard.h index 463ec9ccfb..47d25f5748 100644 --- a/ports/stm32/boards/STM32L476DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32L476DISC/mpconfigboard.h @@ -4,6 +4,7 @@ void STM32L476DISC_board_early_init(void); #define MICROPY_HW_BOARD_NAME "L476-DISCO" #define MICROPY_HW_MCU_NAME "STM32L476" +#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0) #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_ENABLE_RNG (1) @@ -17,6 +18,17 @@ void STM32L476DISC_board_early_init(void); #define MICROPY_HW_SPIFLASH_MOSI (pin_E12) #define MICROPY_HW_SPIFLASH_MISO (pin_E13) +// block device config for SPI flash +extern const struct _mp_spiflash_config_t spiflash_config; +extern struct _spi_bdev_t spi_bdev; +#define MICROPY_HW_BDEV_IOCTL(op, arg) ( \ + (op) == BDEV_IOCTL_NUM_BLOCKS ? (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) : \ + (op) == BDEV_IOCTL_INIT ? spi_bdev_ioctl(&spi_bdev, (op), (uint32_t)&spiflash_config) : \ + spi_bdev_ioctl(&spi_bdev, (op), (arg)) \ +) +#define MICROPY_HW_BDEV_READBLOCKS(dest, bl, n) spi_bdev_readblocks(&spi_bdev, (dest), (bl), (n)) +#define MICROPY_HW_BDEV_WRITEBLOCKS(src, bl, n) spi_bdev_writeblocks(&spi_bdev, (src), (bl), (n)) + // MSI is used and is 4MHz #define MICROPY_HW_CLK_PLLM (1) #define MICROPY_HW_CLK_PLLN (40) From 0d5bccad11f2ccc11e513c3fff3ba65d1f4846b0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 10 Mar 2018 01:03:27 +1100 Subject: [PATCH 445/828] stm32/storage: Provide support for a second block device. --- ports/stm32/storage.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index 4cf2898b32..1450f21565 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -36,6 +36,10 @@ #define FLASH_PART1_START_BLOCK (0x100) +#if defined(MICROPY_HW_BDEV2_IOCTL) +#define FLASH_PART2_START_BLOCK (FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) +#endif + static bool storage_is_initialised = false; void storage_init(void) { @@ -44,6 +48,10 @@ void storage_init(void) { MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_INIT, 0); + #if defined(MICROPY_HW_BDEV2_IOCTL) + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_INIT, 0); + #endif + // Enable the flash IRQ, which is used to also call our storage IRQ handler // It needs to go at a higher priority than all those components that rely on // the flash storage (eg higher than USB MSC). @@ -57,15 +65,25 @@ uint32_t storage_get_block_size(void) { } uint32_t storage_get_block_count(void) { + #if defined(MICROPY_HW_BDEV2_IOCTL) + return FLASH_PART2_START_BLOCK + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0); + #else return FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0); + #endif } void storage_irq_handler(void) { MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_IRQ_HANDLER, 0); + #if defined(MICROPY_HW_BDEV2_IOCTL) + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_IRQ_HANDLER, 0); + #endif } void storage_flush(void) { MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_SYNC, 0); + #if defined(MICROPY_HW_BDEV2_IOCTL) + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_SYNC, 0); + #endif } static void build_partition(uint8_t *buf, int boot, int type, uint32_t start_block, uint32_t num_blocks) { @@ -114,7 +132,11 @@ bool storage_read_block(uint8_t *dest, uint32_t block) { } build_partition(dest + 446, 0, 0x01 /* FAT12 */, FLASH_PART1_START_BLOCK, MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)); + #if defined(MICROPY_HW_BDEV2_IOCTL) + build_partition(dest + 462, 0, 0x01 /* FAT12 */, FLASH_PART2_START_BLOCK, MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)); + #else build_partition(dest + 462, 0, 0, 0, 0); + #endif build_partition(dest + 478, 0, 0, 0, 0); build_partition(dest + 494, 0, 0, 0, 0); @@ -153,6 +175,12 @@ mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_bl } #endif + #if defined(MICROPY_HW_BDEV2_READBLOCKS) + if (FLASH_PART2_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART2_START_BLOCK + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { + return MICROPY_HW_BDEV2_READBLOCKS(dest, block_num - FLASH_PART2_START_BLOCK, num_blocks); + } + #endif + for (size_t i = 0; i < num_blocks; i++) { if (!storage_read_block(dest + i * FLASH_BLOCK_SIZE, block_num + i)) { return 1; // error @@ -168,6 +196,12 @@ mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t } #endif + #if defined(MICROPY_HW_BDEV2_WRITEBLOCKS) + if (FLASH_PART2_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART2_START_BLOCK + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { + return MICROPY_HW_BDEV2_WRITEBLOCKS(src, block_num - FLASH_PART2_START_BLOCK, num_blocks); + } + #endif + for (size_t i = 0; i < num_blocks; i++) { if (!storage_write_block(src + i * FLASH_BLOCK_SIZE, block_num + i)) { return 1; // error From cc34b087f0fe121afb03dcfe99180737ab925372 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 11 Mar 2018 11:25:38 +1100 Subject: [PATCH 446/828] drivers/memory/spiflash: Fix setting of QE bit in flash register. --- drivers/memory/spiflash.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c index ad451f2c5d..c7f333044d 100644 --- a/drivers/memory/spiflash.c +++ b/drivers/memory/spiflash.c @@ -181,8 +181,8 @@ void mp_spiflash_init(mp_spiflash_t *self) { // Set QE bit uint32_t data = (mp_spiflash_read_cmd(self, CMD_RDSR, 1) & 0xff) | (mp_spiflash_read_cmd(self, CMD_RDCR, 1) & 0xff) << 8; - if (!(data & (QSPI_QE_MASK << 16))) { - data |= QSPI_QE_MASK << 16; + if (!(data & (QSPI_QE_MASK << 8))) { + data |= QSPI_QE_MASK << 8; mp_spiflash_write_cmd(self, CMD_WREN); mp_spiflash_write_cmd_data(self, CMD_WRSR, 2, data); mp_spiflash_wait_wip0(self); From 1345093401ed0812aa72dc5206cb8fd5fe61917f Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 11 Mar 2018 18:28:48 +1100 Subject: [PATCH 447/828] stm32/qspi: Do an explicit read instead of using memory-mapped mode. Using an explicit read eliminates the need to invalidate the D-cache after enabling the memory mapping mode, which takes additional time. --- ports/stm32/qspi.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/ports/stm32/qspi.c b/ports/stm32/qspi.c index e1ba38c619..50cf5eb487 100644 --- a/ports/stm32/qspi.c +++ b/ports/stm32/qspi.c @@ -48,6 +48,7 @@ void qspi_init(void) { QUADSPI->CR = 2 << QUADSPI_CR_PRESCALER_Pos // F_CLK = F_AHB/3 (72MHz when CPU is 216MHz) + | 3 << QUADSPI_CR_FTHRES_Pos // 4 bytes must be available to read/write #if defined(QUADSPI_CR_FSEL_Pos) | 0 << QUADSPI_CR_FSEL_Pos // FLASH 1 selected #endif @@ -232,9 +233,37 @@ STATIC uint32_t qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) { STATIC void qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) { (void)self_in; - // This assumes that cmd=0xeb - qspi_memory_map(); - memcpy(dest, (void*)(0x90000000 + addr), len); + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag + + QUADSPI->DLR = len - 1; // number of bytes to read + + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 1 << QUADSPI_CCR_FMODE_Pos // indirect read mode + | 3 << QUADSPI_CCR_DMODE_Pos // data on 4 lines + | 4 << QUADSPI_CCR_DCYC_Pos // 4 dummy cycles + | 0 << QUADSPI_CCR_ABSIZE_Pos // 8-bit alternate byte + | 3 << QUADSPI_CCR_ABMODE_Pos // alternate byte on 4 lines + | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size + | 3 << QUADSPI_CCR_ADMODE_Pos // address on 4 lines + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | cmd << QUADSPI_CCR_INSTRUCTION_Pos // quad read opcode + ; + + QUADSPI->ABR = 0; // alternate byte: disable continuous read mode + QUADSPI->AR = addr; // addres to read from + + // Read in the data + while (len) { + while (!(QUADSPI->SR & QUADSPI_SR_FTF)) { + } + *(uint32_t*)dest = QUADSPI->DR; + dest += 4; + len -= 4; + } + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag } const mp_qspi_proto_t qspi_proto = { From 4d3a92c67c9b1550eaf07d06ed74de996ee8fa3b Mon Sep 17 00:00:00 2001 From: Tom Collins Date: Thu, 8 Mar 2018 16:02:26 -0800 Subject: [PATCH 448/828] extmod/vfs_fat: Add file size as 4th element of uos.ilistdir tuple. --- docs/library/uos.rst | 8 ++++++-- extmod/vfs.c | 4 +--- extmod/vfs_fat.c | 5 +++-- tests/extmod/vfs_fat_fileio1.py.exp | 2 +- tests/extmod/vfs_fat_fileio2.py.exp | 8 ++++---- tests/extmod/vfs_fat_oldproto.py.exp | 2 +- tests/extmod/vfs_fat_ramdisk.py.exp | 4 ++-- 7 files changed, 18 insertions(+), 15 deletions(-) diff --git a/docs/library/uos.rst b/docs/library/uos.rst index 85adb6a4dd..27f339bb16 100644 --- a/docs/library/uos.rst +++ b/docs/library/uos.rst @@ -43,11 +43,11 @@ Filesystem access .. function:: ilistdir([dir]) - This function returns an iterator which then yields 3-tuples corresponding to + This function returns an iterator which then yields tuples corresponding to the entries in the directory that it is listing. With no argument it lists the current directory, otherwise it lists the directory given by *dir*. - The 3-tuples have the form *(name, type, inode)*: + The tuples have the form *(name, type, inode[, size])*: - *name* is a string (or bytes if *dir* is a bytes object) and is the name of the entry; @@ -55,6 +55,10 @@ Filesystem access directories and 0x8000 for regular files; - *inode* is an integer corresponding to the inode of the file, and may be 0 for filesystems that don't have such a notion. + - Some platforms may return a 4-tuple that includes the entry's *size*. For + file entries, *size* is an integer representing the size of the file + or -1 if unknown. Its meaning is currently undefined for directory + entries. .. function:: listdir([dir]) diff --git a/extmod/vfs.c b/extmod/vfs.c index 105a80a8df..0585de1c72 100644 --- a/extmod/vfs.c +++ b/extmod/vfs.c @@ -366,9 +366,7 @@ mp_obj_t mp_vfs_listdir(size_t n_args, const mp_obj_t *args) { mp_obj_t dir_list = mp_obj_new_list(0, NULL); mp_obj_t next; while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { - mp_obj_t *items; - mp_obj_get_array_fixed_n(next, 3, &items); - mp_obj_list_append(dir_list, items[0]); + mp_obj_list_append(dir_list, mp_obj_subscr(next, MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_SENTINEL)); } return dir_list; } diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 0177f5129b..5666a6b0c1 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -142,8 +142,8 @@ STATIC mp_obj_t mp_vfs_fat_ilistdir_it_iternext(mp_obj_t self_in) { // Note that FatFS already filters . and .., so we don't need to - // make 3-tuple with info about this entry - mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); + // make 4-tuple with info about this entry + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL)); if (self->is_str) { t->items[0] = mp_obj_new_str(fn, strlen(fn)); } else { @@ -157,6 +157,7 @@ STATIC mp_obj_t mp_vfs_fat_ilistdir_it_iternext(mp_obj_t self_in) { t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG); } t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number + t->items[3] = mp_obj_new_int_from_uint(fno.fsize); return MP_OBJ_FROM_PTR(t); } diff --git a/tests/extmod/vfs_fat_fileio1.py.exp b/tests/extmod/vfs_fat_fileio1.py.exp index 2d4792aa3b..4eb50402c4 100644 --- a/tests/extmod/vfs_fat_fileio1.py.exp +++ b/tests/extmod/vfs_fat_fileio1.py.exp @@ -10,7 +10,7 @@ e o d True -[('foo_dir', 16384, 0)] +[('foo_dir', 16384, 0, 0)] MemoryError x0 x1 diff --git a/tests/extmod/vfs_fat_fileio2.py.exp b/tests/extmod/vfs_fat_fileio2.py.exp index 118dee26b5..2684053641 100644 --- a/tests/extmod/vfs_fat_fileio2.py.exp +++ b/tests/extmod/vfs_fat_fileio2.py.exp @@ -3,9 +3,9 @@ True True b'data in file' True -[('sub_file.txt', 32768, 0), ('file.txt', 32768, 0)] -[('foo_dir', 16384, 0), ('moved-to-root.txt', 32768, 0)] -[('foo_dir', 16384, 0), ('moved-to-root.txt', 32768, 0)] +[('sub_file.txt', 32768, 0, 11), ('file.txt', 32768, 0, 12)] +[('foo_dir', 16384, 0, 0), ('moved-to-root.txt', 32768, 0, 12)] +[('foo_dir', 16384, 0, 0), ('moved-to-root.txt', 32768, 0, 8)] new text -[('moved-to-root.txt', 32768, 0)] +[('moved-to-root.txt', 32768, 0, 8)] ENOSPC: True diff --git a/tests/extmod/vfs_fat_oldproto.py.exp b/tests/extmod/vfs_fat_oldproto.py.exp index ab8338cbba..b974683167 100644 --- a/tests/extmod/vfs_fat_oldproto.py.exp +++ b/tests/extmod/vfs_fat_oldproto.py.exp @@ -1,3 +1,3 @@ -[('file.txt', 32768, 0)] +[('file.txt', 32768, 0, 6)] hello! [] diff --git a/tests/extmod/vfs_fat_ramdisk.py.exp b/tests/extmod/vfs_fat_ramdisk.py.exp index ccd0f7134c..ef6cf1e72b 100644 --- a/tests/extmod/vfs_fat_ramdisk.py.exp +++ b/tests/extmod/vfs_fat_ramdisk.py.exp @@ -3,7 +3,7 @@ True statvfs: (512, 512, 16, 16, 16, 0, 0, 0, 0, 255) getcwd: / True -[('foo_file.txt', 32768, 0)] +[('foo_file.txt', 32768, 0, 6)] stat root: (16384, 0, 0, 0, 0, 0, 0, 0, 0, 0) stat file: (32768, 0, 0, 0, 0, 0, 6) True @@ -12,5 +12,5 @@ getcwd: /foo_dir [] True getcwd: / -[(b'foo_file.txt', 32768, 0), (b'foo_dir', 16384, 0)] +[(b'foo_file.txt', 32768, 0, 6), (b'foo_dir', 16384, 0, 0)] ENOENT: True From 033c32e694199bbb68816883a857a77711d68a13 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 12 Mar 2018 12:45:09 +1100 Subject: [PATCH 449/828] esp8266/esp_mphal.h: Fix I2C glitching by using input mode for od_high. Certain pins (eg 4 and 5) seem to behave differently at the hardware level when in open-drain mode: they glitch when set "high" and drive the pin active high for a brief period before disabling the output driver. To work around this make the pin an input to let it float high. --- ports/esp8266/esp_mphal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp8266/esp_mphal.h b/ports/esp8266/esp_mphal.h index 194e56f649..940ca47271 100644 --- a/ports/esp8266/esp_mphal.h +++ b/ports/esp8266/esp_mphal.h @@ -86,7 +86,7 @@ void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin); } while (0) #define mp_hal_pin_od_high(p) do { \ if ((p) == 16) { WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1)); } \ - else { gpio_output_set(1 << (p), 0, 1 << (p), 0); } \ + else { gpio_output_set(0, 0, 0, 1 << (p)); /* set as input to avoid glitches */ } \ } while (0) #define mp_hal_pin_read(p) pin_get(p) #define mp_hal_pin_write(p, v) pin_set((p), (v)) From d4b55eff44da38e51616124883508c0d6b6678d3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 13 Mar 2018 13:23:30 +1100 Subject: [PATCH 450/828] py/misc.h: Remove unused count_lead_ones() inline function. This function was never used for unicode/utf8 handling code, or anything else, so remove it to keep things clean. --- py/misc.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/py/misc.h b/py/misc.h index a14bef7fe6..72560da1eb 100644 --- a/py/misc.h +++ b/py/misc.h @@ -204,20 +204,6 @@ int DEBUG_printf(const char *fmt, ...); extern mp_uint_t mp_verbose_flag; -// This is useful for unicode handling. Some CPU archs has -// special instructions for efficient implementation of this -// function (e.g. CLZ on ARM). -// NOTE: this function is unused at the moment -#ifndef count_lead_ones -static inline mp_uint_t count_lead_ones(byte val) { - mp_uint_t c = 0; - for (byte mask = 0x80; val & mask; mask >>= 1) { - c++; - } - return c; -} -#endif - /** float internals *************/ #if MICROPY_PY_BUILTINS_FLOAT From 9f811e9096819230905a5eb47812934531005403 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 13 Mar 2018 14:01:55 +1100 Subject: [PATCH 451/828] py/obj.h: Clean up by removing commented-out inline versions of macros. --- py/obj.h | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/py/obj.h b/py/obj.h index 32b4301545..717e33bbcf 100644 --- a/py/obj.h +++ b/py/obj.h @@ -250,6 +250,8 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t; // The macros below are derived from the ones above and are used to // check for more specific object types. +// Note: these are kept as macros because inline functions sometimes use much +// more code space than the equivalent macros, depending on the compiler. #define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type == (t))) // this does not work for checking int, str or fun; use below macros for that #define MP_OBJ_IS_INT(o) (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int)) @@ -257,17 +259,6 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t; #define MP_OBJ_IS_STR_OR_BYTES(o) (MP_OBJ_IS_QSTR(o) || (MP_OBJ_IS_OBJ(o) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->binary_op == mp_obj_str_binary_op)) #define MP_OBJ_IS_FUN(o) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->name == MP_QSTR_function)) -// Note: inline functions sometimes use much more code space than the -// equivalent macros, depending on the compiler. -//static inline bool MP_OBJ_IS_TYPE(mp_const_obj_t o, const mp_obj_type_t *t) { return (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type == (t))); } // this does not work for checking a string, use below macro for that -//static inline bool MP_OBJ_IS_INT(mp_const_obj_t o) { return (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int)); } // returns true if o is a small int or long int -// Need to forward declare these for the inline function to compile. -extern const mp_obj_type_t mp_type_int; -extern const mp_obj_type_t mp_type_bool; -static inline bool mp_obj_is_integer(mp_const_obj_t o) { return MP_OBJ_IS_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_bool); } // returns true if o is bool, small int or long int -//static inline bool MP_OBJ_IS_STR(mp_const_obj_t o) { return (MP_OBJ_IS_QSTR(o) || MP_OBJ_IS_TYPE(o, &mp_type_str)); } - - // These macros are used to declare and define constant function objects // You can put "static" in front of the definitions to make them local @@ -681,6 +672,7 @@ bool mp_obj_is_true(mp_obj_t arg); bool mp_obj_is_callable(mp_obj_t o_in); bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2); +static inline bool mp_obj_is_integer(mp_const_obj_t o) { return MP_OBJ_IS_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_bool); } // returns true if o is bool, small int or long int mp_int_t mp_obj_get_int(mp_const_obj_t arg); mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg); bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value); From e0bc438e4badb8f2d356479a3bee2b9c45fd69ca Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 13 Mar 2018 14:03:15 +1100 Subject: [PATCH 452/828] py/obj.h: Move declaration of mp_obj_list_init to objlist.h. If this function is used then objlist.h is already included to get the definition of mp_obj_list_t. --- py/obj.h | 2 -- py/objlist.h | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/py/obj.h b/py/obj.h index 717e33bbcf..2779b3f861 100644 --- a/py/obj.h +++ b/py/obj.h @@ -744,8 +744,6 @@ void mp_obj_tuple_del(mp_obj_t self_in); mp_int_t mp_obj_tuple_hash(mp_obj_t self_in); // list -struct _mp_obj_list_t; -void mp_obj_list_init(struct _mp_obj_list_t *o, size_t n); mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg); mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value); void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items); diff --git a/py/objlist.h b/py/objlist.h index 28b5495a92..a43663db76 100644 --- a/py/objlist.h +++ b/py/objlist.h @@ -35,4 +35,6 @@ typedef struct _mp_obj_list_t { mp_obj_t *items; } mp_obj_list_t; +void mp_obj_list_init(mp_obj_list_t *o, size_t n); + #endif // MICROPY_INCLUDED_PY_OBJLIST_H From bdc875e602f687bf0fb28c3a18565ffec4157f59 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 13 Mar 2018 14:13:30 +1100 Subject: [PATCH 453/828] drivers/memory/spiflash: Fix bugs in and clean up read/write functions. mp_spiflash_read had a bug in it where "dest" and "addr" were incremented twice for a certain special case. This was fixed, which then allowed the function to be simplified to reduce code size. mp_spiflash_write had a bug in it where "src" was not incremented correctly for the case where the data to be written included the caching buffer as well as some bytes after this buffer. This was fixed and the resulting code simplified. --- drivers/memory/spiflash.c | 129 +++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 72 deletions(-) diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c index c7f333044d..d72603f648 100644 --- a/drivers/memory/spiflash.c +++ b/drivers/memory/spiflash.c @@ -233,50 +233,32 @@ void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *d mp_spiflash_acquire_bus(self); if (bufuser == self && bufsec != 0xffffffff) { uint32_t bis = addr / SECTOR_SIZE; - int rest = 0; - if (bis < bufsec) { - rest = bufsec * SECTOR_SIZE - addr; - if (rest > len) { - rest = len; - } - mp_spiflash_read_data(self, addr, rest, dest); - len -= rest; - if (len <= 0) { - mp_spiflash_release_bus(self); - return; - } else { - // Something from buffer... - addr = bufsec * SECTOR_SIZE; - dest += rest; - if (len > SECTOR_SIZE) { - rest = SECTOR_SIZE; - } else { - rest = len; - } - memcpy(dest, buf, rest); + uint32_t bie = (addr + len - 1) / SECTOR_SIZE; + if (bis <= bufsec && bufsec <= bie) { + // Read straddles current buffer + size_t rest = 0; + if (bis < bufsec) { + // Read direct from flash for first part + rest = bufsec * SECTOR_SIZE - addr; + mp_spiflash_read_data(self, addr, rest, dest); len -= rest; - if (len <= 0) { - mp_spiflash_release_bus(self); - return; - } dest += rest; addr += rest; } - } else if (bis == bufsec) { - uint32_t offset = addr & (SECTOR_SIZE-1); + uint32_t offset = addr & (SECTOR_SIZE - 1); rest = SECTOR_SIZE - offset; if (rest > len) { rest = len; } memcpy(dest, &buf[offset], rest); len -= rest; - if (len <= 0) { + if (len == 0) { mp_spiflash_release_bus(self); return; } + dest += rest; + addr += rest; } - dest += rest; - addr += rest; } // Read rest direct from flash mp_spiflash_read_data(self, addr, len, dest); @@ -395,64 +377,67 @@ int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint uint32_t bie = (addr + len - 1) / SECTOR_SIZE; mp_spiflash_acquire_bus(self); + if (bufuser == self && bis <= bufsec && bie >= bufsec) { - // Current buffer affected, handle this part first - uint32_t taddr = (bufsec + 1) * SECTOR_SIZE; - int32_t offset = addr - bufsec * SECTOR_SIZE; - int32_t pre = bufsec * SECTOR_SIZE - addr; - if (offset < 0) { + // Write straddles current buffer + uint32_t pre; + uint32_t offset; + if (bufsec * SECTOR_SIZE >= addr) { + pre = bufsec * SECTOR_SIZE - addr; offset = 0; } else { pre = 0; + offset = addr - bufsec * SECTOR_SIZE; } - int32_t rest = len - pre; - int32_t trail = 0; - if (rest > SECTOR_SIZE - offset) { - trail = rest - (SECTOR_SIZE - offset); - rest = SECTOR_SIZE - offset; + + // Write buffered part first + uint32_t len_in_buf = len - pre; + len = 0; + if (len_in_buf > SECTOR_SIZE - offset) { + len = len_in_buf - (SECTOR_SIZE - offset); + len_in_buf = SECTOR_SIZE - offset; } - memcpy(&buf[offset], &src[pre], rest); + memcpy(&buf[offset], &src[pre], len_in_buf); self->flags |= 1; // Mark dirty - if ((pre | trail) == 0) { - mp_spiflash_release_bus(self); - return 0; - } - const uint8_t *p = src; + + // Write part before buffer sector while (pre) { int rest = pre & (SECTOR_SIZE - 1); if (rest == 0) { rest = SECTOR_SIZE; } - mp_spiflash_write_part(self, addr, rest, p); - p += rest; + int ret = mp_spiflash_write_part(self, addr, rest, src); + if (ret != 0) { + mp_spiflash_release_bus(self); + return ret; + } + src += rest; addr += rest; pre -= rest; } - while (trail) { - int rest = trail; - if (rest > SECTOR_SIZE) { - rest = SECTOR_SIZE; - } - mp_spiflash_write_part(self, taddr, rest, src); - src += rest; - taddr += rest; - trail -= rest; - } - } else { - // Current buffer not affected, business as usual - uint32_t offset = addr & (SECTOR_SIZE - 1); - while (len) { - int rest = SECTOR_SIZE - offset; - if (rest > len) { - rest = len; - } - mp_spiflash_write_part(self, addr, rest, src); - len -= rest; - addr += rest; - src += rest; - offset = 0; - } + src += len_in_buf; + addr += len_in_buf; + + // Fall through to write remaining part } + + uint32_t offset = addr & (SECTOR_SIZE - 1); + while (len) { + int rest = SECTOR_SIZE - offset; + if (rest > len) { + rest = len; + } + int ret = mp_spiflash_write_part(self, addr, rest, src); + if (ret != 0) { + mp_spiflash_release_bus(self); + return ret; + } + len -= rest; + addr += rest; + src += rest; + offset = 0; + } + mp_spiflash_release_bus(self); return 0; } From 34e224a4afbacbc8f1621c415b6d3fc42ed84cb8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 14 Mar 2018 13:18:43 +1100 Subject: [PATCH 454/828] esp32/machine_uart: Return None from UART read if no data is available. This is instead of returning an empty bytes object, and matches how other ports handle non-blocking UART read behaviour. --- ports/esp32/machine_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp32/machine_uart.c b/ports/esp32/machine_uart.c index 06d9c0b0da..26cbc88fcd 100644 --- a/ports/esp32/machine_uart.c +++ b/ports/esp32/machine_uart.c @@ -297,7 +297,7 @@ STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t siz int bytes_read = uart_read_bytes(self->uart_num, buf_in, size, time_to_wait); - if (bytes_read < 0) { + if (bytes_read <= 0) { *errcode = MP_EAGAIN; return MP_STREAM_ERROR; } From c926e72750ddc410f2ae4f1b28d17dfb09b5ca2c Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Mar 2018 15:49:38 +1100 Subject: [PATCH 455/828] tests/cpydiff: Indent workaround code snippet so it formats correctly. --- tests/cpydiff/types_exception_subclassinit.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/cpydiff/types_exception_subclassinit.py b/tests/cpydiff/types_exception_subclassinit.py index 56bab51d13..39cdaf45b8 100644 --- a/tests/cpydiff/types_exception_subclassinit.py +++ b/tests/cpydiff/types_exception_subclassinit.py @@ -4,9 +4,9 @@ description: Exception.__init__ method does not exist. cause: Subclassing native classes is not fully supported in MicroPython. workaround: Call using ``super()`` instead:: -class A(Exception): - def __init__(self): - super().__init__() + class A(Exception): + def __init__(self): + super().__init__() """ class A(Exception): def __init__(self): From 0db49c37a4e8d2516ea0206f4e800b907cd4221f Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Mar 2018 15:50:51 +1100 Subject: [PATCH 456/828] docs: Fix some references and RST markup to eliminate Sphinx warnings. --- docs/library/array.rst | 6 +++--- docs/library/lcd160cr.rst | 4 ++-- docs/library/pyb.Switch.rst | 2 +- docs/library/uio.rst | 4 ++-- docs/library/uselect.rst | 8 ++++---- docs/library/ussl.rst | 6 +++--- docs/reference/constrained.rst | 4 ++-- docs/reference/packages.rst | 4 ++-- docs/reference/speed_python.rst | 10 +++++----- 9 files changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/library/array.rst b/docs/library/array.rst index d096c6ec48..f837b03436 100644 --- a/docs/library/array.rst +++ b/docs/library/array.rst @@ -16,14 +16,14 @@ Classes .. class:: array.array(typecode, [iterable]) Create array with elements of given type. Initial contents of the - array are given by an `iterable`. If it is not provided, an empty + array are given by *iterable*. If it is not provided, an empty array is created. .. method:: append(val) - Append new element to the end of array, growing it. + Append new element *val* to the end of array, growing it. .. method:: extend(iterable) - Append new elements as contained in an iterable to the end of + Append new elements as contained in *iterable* to the end of array, growing it. diff --git a/docs/library/lcd160cr.rst b/docs/library/lcd160cr.rst index 567994640b..bb8e6da22c 100644 --- a/docs/library/lcd160cr.rst +++ b/docs/library/lcd160cr.rst @@ -172,7 +172,7 @@ Drawing text ------------ To draw text one sets the position, color and font, and then uses -`write` to draw the text. +`LCD160CR.write` to draw the text. .. method:: LCD160CR.set_pos(x, y) @@ -279,7 +279,7 @@ Touch screen methods .. method:: LCD160CR.is_touched() Returns a boolean: ``True`` if there is currently a touch force on the screen, - `False` otherwise. + ``False`` otherwise. .. method:: LCD160CR.get_touch() diff --git a/docs/library/pyb.Switch.rst b/docs/library/pyb.Switch.rst index e5ab6bd844..1edcbf8488 100644 --- a/docs/library/pyb.Switch.rst +++ b/docs/library/pyb.Switch.rst @@ -38,7 +38,7 @@ Methods .. method:: Switch.value() - Get the switch state. Returns `True` if pressed down, otherwise `False`. + Get the switch state. Returns ``True`` if pressed down, otherwise ``False``. .. method:: Switch.callback(fun) diff --git a/docs/library/uio.rst b/docs/library/uio.rst index 7e6c932284..81420702dc 100644 --- a/docs/library/uio.rst +++ b/docs/library/uio.rst @@ -81,7 +81,7 @@ Functions Open a file. Builtin ``open()`` function is aliased to this function. All ports (which provide access to file system) are required to support - `mode` parameter, but support for other arguments vary by port. + *mode* parameter, but support for other arguments vary by port. Classes ------- @@ -103,7 +103,7 @@ Classes text-mode I/O (similar to a normal file opened with "t" modifier). `BytesIO` is used for binary-mode I/O (similar to a normal file opened with "b" modifier). Initial contents of file-like objects - can be specified with `string` parameter (should be normal string + can be specified with *string* parameter (should be normal string for `StringIO` or bytes object for `BytesIO`). All the usual file methods like ``read()``, ``write()``, ``seek()``, ``flush()``, ``close()`` are available on these objects, and additionally, a diff --git a/docs/library/uselect.rst b/docs/library/uselect.rst index fb43f7e63e..77d4584731 100644 --- a/docs/library/uselect.rst +++ b/docs/library/uselect.rst @@ -35,10 +35,10 @@ Methods Register `stream` *obj* for polling. *eventmask* is logical OR of: - * `uselect.POLLIN` - data available for reading - * `uselect.POLLOUT` - more data can be written + * ``uselect.POLLIN`` - data available for reading + * ``uselect.POLLOUT`` - more data can be written - Note that flags like `uselect.POLLHUP` and `uselect.POLLERR` are + Note that flags like ``uselect.POLLHUP`` and ``uselect.POLLERR`` are *not* valid as input eventmask (these are unsolicited events which will be returned from `poll()` regardless of whether they are asked for). This semantics is per POSIX. @@ -63,7 +63,7 @@ Methods tuple, depending on a platform and version, so don't assume that its size is 2. The ``event`` element specifies which events happened with a stream and is a combination of ``uselect.POLL*`` constants described above. Note that - flags `uselect.POLLHUP` and `uselect.POLLERR` can be returned at any time + flags ``uselect.POLLHUP`` and ``uselect.POLLERR`` can be returned at any time (even if were not asked for), and must be acted on accordingly (the corresponding stream unregistered from poll and likely closed), because otherwise all further invocations of `poll()` may return immediately with diff --git a/docs/library/ussl.rst b/docs/library/ussl.rst index 903a351f4d..be84dc0545 100644 --- a/docs/library/ussl.rst +++ b/docs/library/ussl.rst @@ -18,10 +18,10 @@ Functions Takes a `stream` *sock* (usually usocket.socket instance of ``SOCK_STREAM`` type), and returns an instance of ssl.SSLSocket, which wraps the underlying stream in an SSL context. Returned object has the usual `stream` interface methods like - `read()`, `write()`, etc. In MicroPython, the returned object does not expose - socket interface and methods like `recv()`, `send()`. In particular, a + ``read()``, ``write()``, etc. In MicroPython, the returned object does not expose + socket interface and methods like ``recv()``, ``send()``. In particular, a server-side SSL socket should be created from a normal socket returned from - `accept()` on a non-SSL listening server socket. + :meth:`~usocket.socket.accept()` on a non-SSL listening server socket. Depending on the underlying module implementation in a particular `MicroPython port`, some or all keyword arguments above may be not supported. diff --git a/docs/reference/constrained.rst b/docs/reference/constrained.rst index e7de459bc9..edac0ae681 100644 --- a/docs/reference/constrained.rst +++ b/docs/reference/constrained.rst @@ -185,7 +185,7 @@ a file it will save RAM if this is done in a piecemeal fashion. Rather than creating a large string object, create a substring and feed it to the stream before dealing with the next. -The best way to create dynamic strings is by means of the string `format` +The best way to create dynamic strings is by means of the string ``format()`` method: .. code:: @@ -259,7 +259,7 @@ were a string. **Runtime compiler execution** The Python funcitons `eval` and `exec` invoke the compiler at runtime, which -requires significant amounts of RAM. Note that the `pickle` library from +requires significant amounts of RAM. Note that the ``pickle`` library from `micropython-lib` employs `exec`. It may be more RAM efficient to use the `ujson` library for object serialisation. diff --git a/docs/reference/packages.rst b/docs/reference/packages.rst index e1609985a5..8be2461c2d 100644 --- a/docs/reference/packages.rst +++ b/docs/reference/packages.rst @@ -42,7 +42,7 @@ size, which means that to uncompress a compressed stream, 32KB of contguous memory needs to be allocated. This requirement may be not satisfiable on low-memory devices, which may have total memory available less than that amount, and even if not, a contiguous block like that -may be hard to allocate due to `memory fragmentation`. To accommodate +may be hard to allocate due to memory fragmentation. To accommodate these constraints, MicroPython distribution packages use Gzip compression with the dictionary size of 4K, which should be a suitable compromise with still achieving some compression while being able to uncompressed @@ -243,7 +243,7 @@ the data files as "resources", and abstracting away access to them. Python supports resource access using its "setuptools" library, using ``pkg_resources`` module. MicroPython, following its usual approach, implements subset of the functionality of that module, specifically -`pkg_resources.resource_stream(package, resource)` function. +``pkg_resources.resource_stream(package, resource)`` function. The idea is that an application calls this function, passing a resource identifier, which is a relative path to data file within the specified package (usually top-level application package). It diff --git a/docs/reference/speed_python.rst b/docs/reference/speed_python.rst index 279a1bbcdc..4db60ec14d 100644 --- a/docs/reference/speed_python.rst +++ b/docs/reference/speed_python.rst @@ -63,8 +63,8 @@ used for communication with a device. A typical driver will create the buffer in constructor and use it in its I/O methods which will be called repeatedly. The MicroPython libraries typically provide support for pre-allocated buffers. For -example, objects which support stream interface (e.g., file or UART) provide `read()` -method which allocates new buffer for read data, but also a `readinto()` method +example, objects which support stream interface (e.g., file or UART) provide ``read()`` +method which allocates new buffer for read data, but also a ``readinto()`` method to read data into an existing buffer. Floating Point @@ -109,10 +109,10 @@ the 10K buffer go (be ready for garbage collection), instead of making a long-living memoryview and keeping 10K blocked for GC. Nonetheless, `memoryview` is indispensable for advanced preallocated buffer -management. `readinto()` method discussed above puts data at the beginning +management. ``readinto()`` method discussed above puts data at the beginning of buffer and fills in entire buffer. What if you need to put data in the middle of existing buffer? Just create a memoryview into the needed section -of buffer and pass it to `readinto()`. +of buffer and pass it to ``readinto()``. Identifying the slowest section of code --------------------------------------- @@ -326,7 +326,7 @@ standard approach would be to write mypin.value(mypin.value() ^ 1) # mypin was instantiated as an output pin -This involves the overhead of two calls to the `Pin` instance's :meth:`~machine.Pin.value()` +This involves the overhead of two calls to the :class:`~machine.Pin` instance's :meth:`~machine.Pin.value()` method. This overhead can be eliminated by performing a read/write to the relevant bit of the chip's GPIO port output data register (odr). To facilitate this the ``stm`` module provides a set of constants providing the addresses of the relevant registers. From d91a1989f5e914c20e8bd559fcca3dc91887f167 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Mar 2018 16:12:32 +1100 Subject: [PATCH 457/828] docs/library/pyb.CAN: Update markup to use latest doc conventions. --- docs/library/pyb.CAN.rst | 60 ++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index 232d04d962..7a3a5e9399 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -24,11 +24,11 @@ Constructors .. class:: pyb.CAN(bus, ...) - Construct a CAN object on the given bus. ``bus`` can be 1-2, or 'YA' or 'YB'. + Construct a CAN object on the given bus. *bus* can be 1-2, or ``'YA'`` or ``'YB'``. With no additional parameters, the CAN object is created but not initialised (it has the settings from the last initialisation of the bus, if any). If extra arguments are given, the bus is initialised. - See ``init`` for parameters of initialisation. + See :meth:`CAN.init` for parameters of initialisation. The physical pins of the CAN busses are: @@ -42,7 +42,7 @@ Class Methods Reset and disable all filter banks and assign how many banks should be available for CAN(1). STM32F405 has 28 filter banks that are shared between the two available CAN bus controllers. - This function configures how many filter banks should be assigned to each. ``nr`` is the number of banks + This function configures how many filter banks should be assigned to each. *nr* is the number of banks that will be assigned to CAN(1), the rest of the 28 are assigned to CAN(2). At boot, 14 banks are assigned to each controller. @@ -53,16 +53,16 @@ Methods Initialise the CAN bus with the given parameters: - - ``mode`` is one of: NORMAL, LOOPBACK, SILENT, SILENT_LOOPBACK - - if ``extframe`` is True then the bus uses extended identifiers in the frames + - *mode* is one of: NORMAL, LOOPBACK, SILENT, SILENT_LOOPBACK + - if *extframe* is True then the bus uses extended identifiers in the frames (29 bits); otherwise it uses standard 11 bit identifiers - - ``prescaler`` is used to set the duration of 1 time quanta; the time quanta + - *prescaler* is used to set the duration of 1 time quanta; the time quanta will be the input clock (PCLK1, see :meth:`pyb.freq()`) divided by the prescaler - - ``sjw`` is the resynchronisation jump width in units of the time quanta; + - *sjw* is the resynchronisation jump width in units of the time quanta; it can be 1, 2, 3, 4 - - ``bs1`` defines the location of the sample point in units of the time quanta; + - *bs1* defines the location of the sample point in units of the time quanta; it can be between 1 and 1024 inclusive - - ``bs2`` defines the location of the transmit point in units of the time quanta; + - *bs2* defines the location of the transmit point in units of the time quanta; it can be between 1 and 16 inclusive The time quanta tq is the basic unit of time for the CAN bus. tq is the CAN @@ -89,13 +89,13 @@ Methods Configure a filter bank: - - ``bank`` is the filter bank that is to be configured. - - ``mode`` is the mode the filter should operate in. - - ``fifo`` is which fifo (0 or 1) a message should be stored in, if it is accepted by this filter. - - ``params`` is an array of values the defines the filter. The contents of the array depends on the ``mode`` argument. + - *bank* is the filter bank that is to be configured. + - *mode* is the mode the filter should operate in. + - *fifo* is which fifo (0 or 1) a message should be stored in, if it is accepted by this filter. + - *params* is an array of values the defines the filter. The contents of the array depends on the *mode* argument. +-----------+---------------------------------------------------------+ - |``mode`` |contents of parameter array | + |*mode* |contents of *params* array | +===========+=========================================================+ |CAN.LIST16 |Four 16 bit ids that will be accepted | +-----------+---------------------------------------------------------+ @@ -110,13 +110,13 @@ Methods |CAN.MASK32 |As with CAN.MASK16 but with only one 32 bit id/mask pair.| +-----------+---------------------------------------------------------+ - - ``rtr`` is an array of booleans that states if a filter should accept a + - *rtr* is an array of booleans that states if a filter should accept a remote transmission request message. If this argument is not given - then it defaults to False for all entries. The length of the array - depends on the ``mode`` argument. + then it defaults to ``False`` for all entries. The length of the array + depends on the *mode* argument. +-----------+----------------------+ - |``mode`` |length of rtr array | + |*mode* |length of *rtr* array | +===========+======================+ |CAN.LIST16 |4 | +-----------+----------------------+ @@ -131,7 +131,7 @@ Methods Clear and disables a filter bank: - - ``bank`` is the filter bank that is to be cleared. + - *bank* is the filter bank that is to be cleared. .. method:: CAN.any(fifo) @@ -141,8 +141,8 @@ Methods Receive data on the bus: - - ``fifo`` is an integer, which is the FIFO to receive on - - ``timeout`` is the timeout in milliseconds to wait for the receive. + - *fifo* is an integer, which is the FIFO to receive on + - *timeout* is the timeout in milliseconds to wait for the receive. Return value: A tuple containing four values. @@ -155,13 +155,13 @@ Methods Send a message on the bus: - - ``data`` is the data to send (an integer to send, or a buffer object). - - ``id`` is the id of the message to be sent. - - ``timeout`` is the timeout in milliseconds to wait for the send. - - ``rtr`` is a boolean that specifies if the message shall be sent as - a remote transmission request. If ``rtr`` is True then only the length - of ``data`` is used to fill in the DLC slot of the frame; the actual - bytes in ``data`` are unused. + - *data* is the data to send (an integer to send, or a buffer object). + - *id* is the id of the message to be sent. + - *timeout* is the timeout in milliseconds to wait for the send. + - *rtr* is a boolean that specifies if the message shall be sent as + a remote transmission request. If *rtr* is True then only the length + of *data* is used to fill in the DLC slot of the frame; the actual + bytes in *data* are unused. If timeout is 0 the message is placed in a buffer in one of three hardware buffers and the method returns immediately. If all three buffers are in use @@ -175,8 +175,8 @@ Methods Register a function to be called when a message is accepted into a empty fifo: - - ``fifo`` is the receiving fifo. - - ``fun`` is the function to be called when the fifo becomes non empty. + - *fifo* is the receiving fifo. + - *fun* is the function to be called when the fifo becomes non empty. The callback function takes two arguments the first is the can object it self the second is a integer that indicates the reason for the callback. From 22a9158ced8c7640ce25abdf41ae4595bd1efa07 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Mar 2018 16:32:11 +1100 Subject: [PATCH 458/828] stm32/boards/STM32L476DISC: Enable CAN peripheral. This board allows to test CAN support on the L4 series. --- ports/stm32/boards/STM32L476DISC/mpconfigboard.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm32/boards/STM32L476DISC/mpconfigboard.h b/ports/stm32/boards/STM32L476DISC/mpconfigboard.h index 47d25f5748..3d8b74e4ab 100644 --- a/ports/stm32/boards/STM32L476DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32L476DISC/mpconfigboard.h @@ -9,6 +9,7 @@ void STM32L476DISC_board_early_init(void); #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_CAN (1) #define MICROPY_HW_ENABLE_USB (1) // use external SPI flash for storage From 2036196d7108ad20c1e4966a84ae2b255e88aa43 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Mar 2018 16:34:07 +1100 Subject: [PATCH 459/828] stm32/can: Improve can.recv() so it checks for events, eg ctrl-C. This patch provides a custom (and simple) function to receive data on the CAN bus, instead of the HAL function. This custom version calls mp_handle_pending() while waiting for messages, which, among other things, allows to interrupt the recv() method via KeyboardInterrupt. --- ports/stm32/can.c | 47 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/ports/stm32/can.c b/ports/stm32/can.c index 3d94b191c6..84b22bb3db 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2014 Damien P. George + * Copyright (c) 2014-2018 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -172,6 +172,43 @@ STATIC void can_clearfilter(uint32_t f) { HAL_CAN_ConfigFilter(NULL, &filter); } +STATIC int can_receive(CAN_TypeDef *can, int fifo, CanRxMsgTypeDef *msg, uint32_t timeout_ms) { + volatile uint32_t *rfr; + if (fifo == CAN_FIFO0) { + rfr = &can->RF0R; + } else { + rfr = &can->RF1R; + } + + // Wait for a message to become available, with timeout + uint32_t start = HAL_GetTick(); + while ((*rfr & 3) == 0) { + MICROPY_EVENT_POLL_HOOK + if (HAL_GetTick() - start >= timeout_ms) { + return -MP_ETIMEDOUT; + } + } + + // Read message data + CAN_FIFOMailBox_TypeDef *box = &can->sFIFOMailBox[fifo]; + msg->IDE = box->RIR & 4; + if (msg->IDE == CAN_ID_STD) { + msg->StdId = box->RIR >> 21; + } else { + msg->ExtId = box->RIR >> 3; + } + msg->RTR = box->RIR & 2; + msg->DLC = box->RDTR & 0xf; + msg->FMI = box->RDTR >> 8 & 0xff; + *(uint32_t*)&msg->Data[0] = box->RDLR; + *(uint32_t*)&msg->Data[4] = box->RDHR; + + // Release (free) message from FIFO + *rfr |= CAN_RF0R_RFOM0; + + return 0; // success +} + // We have our own version of CAN transmit so we can handle Timeout=0 correctly. STATIC HAL_StatusTypeDef CAN_Transmit(CAN_HandleTypeDef *hcan, uint32_t Timeout) { uint32_t transmitmailbox; @@ -530,11 +567,9 @@ STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t * // receive the data CanRxMsgTypeDef rx_msg; - self->can.pRxMsg = self->can.pRx1Msg = &rx_msg; - HAL_StatusTypeDef status = HAL_CAN_Receive(&self->can, args[0].u_int, args[1].u_int); - - if (status != HAL_OK) { - mp_hal_raise(status); + int ret = can_receive(self->can.Instance, args[0].u_int, &rx_msg, args[1].u_int); + if (ret < 0) { + mp_raise_OSError(-ret); } // Manage the rx state machine From 1608c4f5bef361894009828f51f0f576cbefd943 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Mar 2018 17:15:41 +1100 Subject: [PATCH 460/828] stm32/can: Use enums to index keyword arguments, for clarity. --- ports/stm32/can.c | 79 +++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/ports/stm32/can.c b/ports/stm32/can.c index 84b22bb3db..d73ca95d40 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -327,6 +327,7 @@ STATIC void pyb_can_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki // init(mode, extframe=False, prescaler=100, *, sjw=1, bs1=6, bs2=8) STATIC mp_obj_t pyb_can_init_helper(pyb_can_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_mode, ARG_extframe, ARG_prescaler, ARG_sjw, ARG_bs1, ARG_bs2 }; static const mp_arg_t allowed_args[] = { { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = CAN_MODE_NORMAL} }, { MP_QSTR_extframe, MP_ARG_BOOL, {.u_bool = false} }, @@ -340,16 +341,16 @@ STATIC mp_obj_t pyb_can_init_helper(pyb_can_obj_t *self, size_t n_args, const mp mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - self->extframe = args[1].u_bool; + self->extframe = args[ARG_extframe].u_bool; // set the CAN configuration values memset(&self->can, 0, sizeof(self->can)); CAN_InitTypeDef *init = &self->can.Init; - init->Mode = args[0].u_int << 4; // shift-left so modes fit in a small-int - init->Prescaler = args[2].u_int; - init->SJW = ((args[3].u_int - 1) & 3) << 24; - init->BS1 = ((args[4].u_int - 1) & 0xf) << 16; - init->BS2 = ((args[5].u_int - 1) & 7) << 20; + init->Mode = args[ARG_mode].u_int << 4; // shift-left so modes fit in a small-int + init->Prescaler = args[ARG_prescaler].u_int; + init->SJW = ((args[ARG_sjw].u_int - 1) & 3) << 24; + init->BS1 = ((args[ARG_bs1].u_int - 1) & 0xf) << 16; + init->BS2 = ((args[ARG_bs2].u_int - 1) & 7) << 20; init->TTCM = DISABLE; init->ABOM = DISABLE; init->AWUM = DISABLE; @@ -495,6 +496,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_can_any_obj, pyb_can_any); /// /// Return value: `None`. STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_data, ARG_id, ARG_timeout, ARG_rtr }; static const mp_arg_t allowed_args[] = { { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, @@ -510,7 +512,7 @@ STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t * // get the buffer to send from mp_buffer_info_t bufinfo; uint8_t data[1]; - pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data); + pyb_buf_get_for_send(args[ARG_data].u_obj, &bufinfo, data); if (bufinfo.len > 8) { mp_raise_ValueError("CAN data field too long"); @@ -519,13 +521,13 @@ STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t * // send the data CanTxMsgTypeDef tx_msg; if (self->extframe) { - tx_msg.ExtId = args[1].u_int & 0x1FFFFFFF; + tx_msg.ExtId = args[ARG_id].u_int & 0x1FFFFFFF; tx_msg.IDE = CAN_ID_EXT; } else { - tx_msg.StdId = args[1].u_int & 0x7FF; + tx_msg.StdId = args[ARG_id].u_int & 0x7FF; tx_msg.IDE = CAN_ID_STD; } - if (args[3].u_bool == false) { + if (args[ARG_rtr].u_bool == false) { tx_msg.RTR = CAN_RTR_DATA; } else { tx_msg.RTR = CAN_RTR_REMOTE; @@ -536,7 +538,7 @@ STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t * } self->can.pTxMsg = &tx_msg; - HAL_StatusTypeDef status = CAN_Transmit(&self->can, args[2].u_int); + HAL_StatusTypeDef status = CAN_Transmit(&self->can, args[ARG_timeout].u_int); if (status != HAL_OK) { mp_hal_raise(status); @@ -555,6 +557,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_send_obj, 1, pyb_can_send); /// /// Return value: buffer of data bytes. STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_fifo, ARG_timeout }; static const mp_arg_t allowed_args[] = { { MP_QSTR_fifo, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, @@ -567,33 +570,34 @@ STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t * // receive the data CanRxMsgTypeDef rx_msg; - int ret = can_receive(self->can.Instance, args[0].u_int, &rx_msg, args[1].u_int); + int ret = can_receive(self->can.Instance, args[ARG_fifo].u_int, &rx_msg, args[ARG_timeout].u_int); if (ret < 0) { mp_raise_OSError(-ret); } // Manage the rx state machine - if ((args[0].u_int == CAN_FIFO0 && self->rxcallback0 != mp_const_none) || - (args[0].u_int == CAN_FIFO1 && self->rxcallback1 != mp_const_none)) { - byte *state = (args[0].u_int == CAN_FIFO0) ? &self->rx_state0 : &self->rx_state1; + mp_int_t fifo = args[ARG_fifo].u_int; + if ((fifo == CAN_FIFO0 && self->rxcallback0 != mp_const_none) || + (fifo == CAN_FIFO1 && self->rxcallback1 != mp_const_none)) { + byte *state = (fifo == CAN_FIFO0) ? &self->rx_state0 : &self->rx_state1; switch (*state) { case RX_STATE_FIFO_EMPTY: break; case RX_STATE_MESSAGE_PENDING: - if (__HAL_CAN_MSG_PENDING(&self->can, args[0].u_int) == 0) { + if (__HAL_CAN_MSG_PENDING(&self->can, fifo) == 0) { // Fifo is empty - __HAL_CAN_ENABLE_IT(&self->can, (args[0].u_int == CAN_FIFO0) ? CAN_IT_FMP0 : CAN_IT_FMP1); + __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FMP0 : CAN_IT_FMP1); *state = RX_STATE_FIFO_EMPTY; } break; case RX_STATE_FIFO_FULL: - __HAL_CAN_ENABLE_IT(&self->can, (args[0].u_int == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1); + __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1); *state = RX_STATE_MESSAGE_PENDING; break; case RX_STATE_FIFO_OVERFLOW: - __HAL_CAN_ENABLE_IT(&self->can, (args[0].u_int == CAN_FIFO0) ? CAN_IT_FOV0 : CAN_IT_FOV1); - __HAL_CAN_ENABLE_IT(&self->can, (args[0].u_int == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1); + __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FOV0 : CAN_IT_FOV1); + __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1); *state = RX_STATE_MESSAGE_PENDING; break; } @@ -656,6 +660,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_can_clearfilter_obj, pyb_can_clearfilter); /// Return value: `None`. #define EXTENDED_ID_TO_16BIT_FILTER(id) (((id & 0xC00000) >> 13) | ((id & 0x38000) >> 15)) | 8 STATIC mp_obj_t pyb_can_setfilter(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_bank, ARG_mode, ARG_fifo, ARG_params, ARG_rtr }; static const mp_arg_t allowed_args[] = { { MP_QSTR_bank, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, @@ -674,20 +679,20 @@ STATIC mp_obj_t pyb_can_setfilter(size_t n_args, const mp_obj_t *pos_args, mp_ma mp_uint_t rtr_masks[4] = {0, 0, 0, 0}; mp_obj_t *rtr_flags; mp_obj_t *params; - mp_obj_get_array(args[3].u_obj, &len, ¶ms); - if (args[4].u_obj != MP_OBJ_NULL){ - mp_obj_get_array(args[4].u_obj, &rtr_len, &rtr_flags); + mp_obj_get_array(args[ARG_params].u_obj, &len, ¶ms); + if (args[ARG_rtr].u_obj != MP_OBJ_NULL){ + mp_obj_get_array(args[ARG_rtr].u_obj, &rtr_len, &rtr_flags); } CAN_FilterConfTypeDef filter; - if (args[1].u_int == MASK16 || args[1].u_int == LIST16) { + if (args[ARG_mode].u_int == MASK16 || args[ARG_mode].u_int == LIST16) { if (len != 4) { goto error; } filter.FilterScale = CAN_FILTERSCALE_16BIT; if (self->extframe) { - if (args[4].u_obj != MP_OBJ_NULL) { - if (args[1].u_int == MASK16) { + if (args[ARG_rtr].u_obj != MP_OBJ_NULL) { + if (args[ARG_mode].u_int == MASK16) { rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0; rtr_masks[1] = 0x02; rtr_masks[2] = mp_obj_get_int(rtr_flags[1]) ? 0x02 : 0; @@ -704,8 +709,8 @@ STATIC mp_obj_t pyb_can_setfilter(size_t n_args, const mp_obj_t *pos_args, mp_ma filter.FilterIdHigh = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[2])) | rtr_masks[2]; // id2 filter.FilterMaskIdHigh = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[3])) | rtr_masks[3]; // mask2 } else { // Basic frames - if (args[4].u_obj != MP_OBJ_NULL) { - if (args[1].u_int == MASK16) { + if (args[ARG_rtr].u_obj != MP_OBJ_NULL) { + if (args[ARG_mode].u_int == MASK16) { rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x10 : 0; rtr_masks[1] = 0x10; rtr_masks[2] = mp_obj_get_int(rtr_flags[1]) ? 0x10 : 0; @@ -722,20 +727,20 @@ STATIC mp_obj_t pyb_can_setfilter(size_t n_args, const mp_obj_t *pos_args, mp_ma filter.FilterIdHigh = (mp_obj_get_int(params[2]) << 5) | rtr_masks[2]; // id2 filter.FilterMaskIdHigh = (mp_obj_get_int(params[3]) << 5) | rtr_masks[3]; // mask2 } - if (args[1].u_int == MASK16) { + if (args[ARG_mode].u_int == MASK16) { filter.FilterMode = CAN_FILTERMODE_IDMASK; } - if (args[1].u_int == LIST16) { + if (args[ARG_mode].u_int == LIST16) { filter.FilterMode = CAN_FILTERMODE_IDLIST; } } - else if (args[1].u_int == MASK32 || args[1].u_int == LIST32) { + else if (args[ARG_mode].u_int == MASK32 || args[ARG_mode].u_int == LIST32) { if (len != 2) { goto error; } filter.FilterScale = CAN_FILTERSCALE_32BIT; - if (args[4].u_obj != MP_OBJ_NULL) { - if (args[1].u_int == MASK32) { + if (args[ARG_rtr].u_obj != MP_OBJ_NULL) { + if (args[ARG_mode].u_int == MASK32) { rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0; rtr_masks[1] = 0x02; } else { // LIST32 @@ -747,18 +752,18 @@ STATIC mp_obj_t pyb_can_setfilter(size_t n_args, const mp_obj_t *pos_args, mp_ma filter.FilterIdLow = (((mp_obj_get_int(params[0]) & 0x00001FFF) << 3) | 4) | rtr_masks[0]; filter.FilterMaskIdHigh = (mp_obj_get_int(params[1]) & 0x1FFFE000 ) >> 13; filter.FilterMaskIdLow = (((mp_obj_get_int(params[1]) & 0x00001FFF) << 3) | 4) | rtr_masks[1]; - if (args[1].u_int == MASK32) { + if (args[ARG_mode].u_int == MASK32) { filter.FilterMode = CAN_FILTERMODE_IDMASK; } - if (args[1].u_int == LIST32) { + if (args[ARG_mode].u_int == LIST32) { filter.FilterMode = CAN_FILTERMODE_IDLIST; } } else { goto error; } - filter.FilterFIFOAssignment = args[2].u_int; // fifo - filter.FilterNumber = args[0].u_int; // bank + filter.FilterFIFOAssignment = args[ARG_fifo].u_int; + filter.FilterNumber = args[ARG_bank].u_int; if (self->can_id == 1) { if (filter.FilterNumber >= can2_start_bank) { goto error; From 823ca03008908d98671393c00b018349d18b46a2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Mar 2018 17:17:33 +1100 Subject: [PATCH 461/828] stm32/can: Add "auto_restart" option to constructor and init() method. --- docs/library/pyb.CAN.rst | 4 +++- ports/stm32/can.c | 18 ++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index 7a3a5e9399..6e5b958cfd 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -49,7 +49,7 @@ Class Methods Methods ------- -.. method:: CAN.init(mode, extframe=False, prescaler=100, \*, sjw=1, bs1=6, bs2=8) +.. method:: CAN.init(mode, extframe=False, prescaler=100, \*, sjw=1, bs1=6, bs2=8, auto_restart=False) Initialise the CAN bus with the given parameters: @@ -64,6 +64,8 @@ Methods it can be between 1 and 1024 inclusive - *bs2* defines the location of the transmit point in units of the time quanta; it can be between 1 and 16 inclusive + - *auto_restart* sets whether the controller will automatically try and restart + communications after entering the bus-off state The time quanta tq is the basic unit of time for the CAN bus. tq is the CAN prescaler value divided by PCLK1 (the frequency of internal peripheral bus 1); diff --git a/ports/stm32/can.c b/ports/stm32/can.c index d73ca95d40..fc0fa98a89 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -307,7 +307,6 @@ STATIC void pyb_can_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki if (!self->is_enabled) { mp_printf(print, "CAN(%u)", self->can_id); } else { - mp_printf(print, "CAN(%u, CAN.", self->can_id); qstr mode; switch (self->can.Init.Mode) { case CAN_MODE_NORMAL: mode = MP_QSTR_NORMAL; break; @@ -315,19 +314,17 @@ STATIC void pyb_can_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki case CAN_MODE_SILENT: mode = MP_QSTR_SILENT; break; case CAN_MODE_SILENT_LOOPBACK: default: mode = MP_QSTR_SILENT_LOOPBACK; break; } - mp_printf(print, "%q, extframe=", mode); - if (self->extframe) { - mode = MP_QSTR_True; - } else { - mode = MP_QSTR_False; - } - mp_printf(print, "%q)", mode); + mp_printf(print, "CAN(%u, CAN.%q, extframe=%q, auto_restart=%q)", + self->can_id, + mode, + self->extframe ? MP_QSTR_True : MP_QSTR_False, + (self->can.Instance->MCR & CAN_MCR_ABOM) ? MP_QSTR_True : MP_QSTR_False); } } // init(mode, extframe=False, prescaler=100, *, sjw=1, bs1=6, bs2=8) STATIC mp_obj_t pyb_can_init_helper(pyb_can_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_mode, ARG_extframe, ARG_prescaler, ARG_sjw, ARG_bs1, ARG_bs2 }; + enum { ARG_mode, ARG_extframe, ARG_prescaler, ARG_sjw, ARG_bs1, ARG_bs2, ARG_auto_restart }; static const mp_arg_t allowed_args[] = { { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = CAN_MODE_NORMAL} }, { MP_QSTR_extframe, MP_ARG_BOOL, {.u_bool = false} }, @@ -335,6 +332,7 @@ STATIC mp_obj_t pyb_can_init_helper(pyb_can_obj_t *self, size_t n_args, const mp { MP_QSTR_sjw, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, { MP_QSTR_bs1, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 6} }, { MP_QSTR_bs2, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_auto_restart, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; // parse args @@ -352,7 +350,7 @@ STATIC mp_obj_t pyb_can_init_helper(pyb_can_obj_t *self, size_t n_args, const mp init->BS1 = ((args[ARG_bs1].u_int - 1) & 0xf) << 16; init->BS2 = ((args[ARG_bs2].u_int - 1) & 7) << 20; init->TTCM = DISABLE; - init->ABOM = DISABLE; + init->ABOM = args[ARG_auto_restart].u_bool ? ENABLE : DISABLE; init->AWUM = DISABLE; init->NART = DISABLE; init->RFLM = DISABLE; From 1272c3c65d895e4694e0c707a98a739706667d23 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Mar 2018 17:29:30 +1100 Subject: [PATCH 462/828] stm32/can: Add CAN.restart() method so controller can leave bus-off. --- docs/library/pyb.CAN.rst | 14 +++++++++++++- ports/stm32/can.c | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index 6e5b958cfd..f90e7a8a7e 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -65,7 +65,8 @@ Methods - *bs2* defines the location of the transmit point in units of the time quanta; it can be between 1 and 16 inclusive - *auto_restart* sets whether the controller will automatically try and restart - communications after entering the bus-off state + communications after entering the bus-off state; if this is disabled then + :meth:`~CAN.restart()` can be used to leave the bus-off state The time quanta tq is the basic unit of time for the CAN bus. tq is the CAN prescaler value divided by PCLK1 (the frequency of internal peripheral bus 1); @@ -87,6 +88,17 @@ Methods Turn off the CAN bus. +.. method:: CAN.restart() + + Force a software restart of the CAN controller without resetting its + configuration. + + If the controller enters the bus-off state then it will no longer participate + in bus activity. If the controller is not configured to automatically restart + (see :meth:`~CAN.init()`) then this method can be used to trigger a restart, + and the controller will follow the CAN protocol to leave the bus-off state and + go into the error active state. + .. method:: CAN.setfilter(bank, mode, fifo, params, \*, rtr) Configure a filter bank: diff --git a/ports/stm32/can.c b/ports/stm32/can.c index fc0fa98a89..d5702f6d1b 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -467,6 +467,23 @@ STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_deinit_obj, pyb_can_deinit); +// Force a software restart of the controller, to allow transmission after a bus error +STATIC mp_obj_t pyb_can_restart(mp_obj_t self_in) { + pyb_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (!self->is_enabled) { + mp_raise_ValueError(NULL); + } + CAN_TypeDef *can = self->can.Instance; + can->MCR |= CAN_MCR_INRQ; + while ((can->MSR & CAN_MSR_INAK) == 0) { + } + can->MCR &= ~CAN_MCR_INRQ; + while ((can->MSR & CAN_MSR_INAK)) { + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_restart_obj, pyb_can_restart); + /// \method any(fifo) /// Return `True` if any message waiting on the FIFO, else `False`. STATIC mp_obj_t pyb_can_any(mp_obj_t self_in, mp_obj_t fifo_in) { @@ -824,6 +841,7 @@ STATIC const mp_rom_map_elem_t pyb_can_locals_dict_table[] = { // instance methods { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_can_init_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_can_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&pyb_can_restart_obj) }, { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&pyb_can_any_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_can_send_obj) }, { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_can_recv_obj) }, From d7e67fb1b40c40ba24e3a17e73e5f1b5b96f3914 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 16 Mar 2018 17:10:41 +1100 Subject: [PATCH 463/828] stm32/can: Add CAN.state() method to get the state of the controller. This is useful for monitoring errors on the bus and knowing when a restart is needed. --- docs/library/pyb.CAN.rst | 22 ++++++++++++++++++++++ ports/stm32/can.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index f90e7a8a7e..484a00f364 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -99,6 +99,20 @@ Methods and the controller will follow the CAN protocol to leave the bus-off state and go into the error active state. +.. method:: CAN.state() + + Return the state of the controller. The return value can be one of: + + - ``CAN.STOPPED`` -- the controller is completely off and reset; + - ``CAN.ERROR_ACTIVE`` -- the controller is on and in the Error Active state + (both TEC and REC are less than 96); + - ``CAN.ERROR_WARNING`` -- the controller is on and in the Error Warning state + (at least one of TEC or REC is 96 or greater); + - ``CAN.ERROR_PASSIVE`` -- the controller is on and in the Error Passive state + (at least one of TEC or REC is 128 or greater); + - ``CAN.BUS_OFF`` -- the controller is on but not participating in bus activity + (TEC overflowed beyond 255). + .. method:: CAN.setfilter(bank, mode, fifo, params, \*, rtr) Configure a filter bank: @@ -229,6 +243,14 @@ Constants the mode of the CAN bus +.. data:: CAN.STOPPED + CAN.ERROR_ACTIVE + CAN.ERROR_WARNING + CAN.ERROR_PASSIVE + CAN.BUS_OFF + + Possible states of the CAN controller. + .. data:: CAN.LIST16 .. data:: CAN.MASK16 .. data:: CAN.LIST32 diff --git a/ports/stm32/can.c b/ports/stm32/can.c index d5702f6d1b..563d15dab3 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -45,6 +45,14 @@ #define MASK32 (2) #define LIST32 (3) +enum { + CAN_STATE_STOPPED, + CAN_STATE_ERROR_ACTIVE, + CAN_STATE_ERROR_WARNING, + CAN_STATE_ERROR_PASSIVE, + CAN_STATE_BUS_OFF, +}; + /// \moduleref pyb /// \class CAN - controller area network communication bus /// @@ -484,6 +492,26 @@ STATIC mp_obj_t pyb_can_restart(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_restart_obj, pyb_can_restart); +// Get the state of the controller +STATIC mp_obj_t pyb_can_state(mp_obj_t self_in) { + pyb_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t state = CAN_STATE_STOPPED; + if (self->is_enabled) { + CAN_TypeDef *can = self->can.Instance; + if (can->ESR & CAN_ESR_BOFF) { + state = CAN_STATE_BUS_OFF; + } else if (can->ESR & CAN_ESR_EPVF) { + state = CAN_STATE_ERROR_PASSIVE; + } else if (can->ESR & CAN_ESR_EWGF) { + state = CAN_STATE_ERROR_WARNING; + } else { + state = CAN_STATE_ERROR_ACTIVE; + } + } + return MP_OBJ_NEW_SMALL_INT(state); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_state_obj, pyb_can_state); + /// \method any(fifo) /// Return `True` if any message waiting on the FIFO, else `False`. STATIC mp_obj_t pyb_can_any(mp_obj_t self_in, mp_obj_t fifo_in) { @@ -842,6 +870,7 @@ STATIC const mp_rom_map_elem_t pyb_can_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_can_init_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_can_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&pyb_can_restart_obj) }, + { MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&pyb_can_state_obj) }, { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&pyb_can_any_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_can_send_obj) }, { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_can_recv_obj) }, @@ -861,6 +890,13 @@ STATIC const mp_rom_map_elem_t pyb_can_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_LIST16), MP_ROM_INT(LIST16) }, { MP_ROM_QSTR(MP_QSTR_MASK32), MP_ROM_INT(MASK32) }, { MP_ROM_QSTR(MP_QSTR_LIST32), MP_ROM_INT(LIST32) }, + + // values for CAN.state() + { MP_ROM_QSTR(MP_QSTR_STOPPED), MP_ROM_INT(CAN_STATE_STOPPED) }, + { MP_ROM_QSTR(MP_QSTR_ERROR_ACTIVE), MP_ROM_INT(CAN_STATE_ERROR_ACTIVE) }, + { MP_ROM_QSTR(MP_QSTR_ERROR_WARNING), MP_ROM_INT(CAN_STATE_ERROR_WARNING) }, + { MP_ROM_QSTR(MP_QSTR_ERROR_PASSIVE), MP_ROM_INT(CAN_STATE_ERROR_PASSIVE) }, + { MP_ROM_QSTR(MP_QSTR_BUS_OFF), MP_ROM_INT(CAN_STATE_BUS_OFF) }, }; STATIC MP_DEFINE_CONST_DICT(pyb_can_locals_dict, pyb_can_locals_dict_table); From a25e6c6b650acf3af742920c1d3a024054c986cb Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 16 Mar 2018 18:28:35 +1100 Subject: [PATCH 464/828] stm32/can: Add CAN.info() method to retrieve error and tx/rx buf info. --- docs/library/pyb.CAN.rst | 22 ++++++++++++++ ports/stm32/can.c | 62 ++++++++++++++++++++++++++++++++++++++++ ports/stm32/can.h | 1 + ports/stm32/stm32_it.c | 12 ++++++++ 4 files changed, 97 insertions(+) diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index 484a00f364..e1ce90d60d 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -113,6 +113,28 @@ Methods - ``CAN.BUS_OFF`` -- the controller is on but not participating in bus activity (TEC overflowed beyond 255). +.. method:: CAN.info([list]) + + Get information about the controller's error states and TX and RX buffers. + If *list* is provided then it should be a list object with at least 8 entries, + which will be filled in with the information. Otherwise a new list will be + created and filled in. In both cases the return value of the method is the + populated list. + + The values in the list are: + + - TEC value + - REC value + - number of times the controller enterted the Error Warning state (wrapped + around to 0 after 65535) + - number of times the controller enterted the Error Passive state (wrapped + around to 0 after 65535) + - number of times the controller enterted the Bus Off state (wrapped + around to 0 after 65535) + - number of pending TX messages + - number of pending RX messages on fifo 0 + - number of pending RX messages on fifo 1 + .. method:: CAN.setfilter(bank, mode, fifo, params, \*, rtr) Configure a filter bank: diff --git a/ports/stm32/can.c b/ports/stm32/can.c index 563d15dab3..b1bcd1c3e6 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -89,6 +89,9 @@ typedef struct _pyb_can_obj_t { bool extframe : 1; byte rx_state0; byte rx_state1; + uint16_t num_error_warning; + uint16_t num_error_passive; + uint16_t num_bus_off; CAN_HandleTypeDef can; } pyb_can_obj_t; @@ -103,6 +106,7 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { uint32_t GPIO_Pin = 0; uint8_t GPIO_AF_CANx = 0; GPIO_TypeDef* GPIO_Port = NULL; + uint32_t sce_irq = 0; switch (can_obj->can_id) { // CAN1 is on RX,TX = Y3,Y4 = PB9,PB9 @@ -111,6 +115,7 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { GPIO_AF_CANx = GPIO_AF9_CAN1; GPIO_Port = GPIOB; GPIO_Pin = GPIO_PIN_8 | GPIO_PIN_9; + sce_irq = CAN1_SCE_IRQn; __CAN1_CLK_ENABLE(); break; @@ -121,6 +126,7 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { GPIO_AF_CANx = GPIO_AF9_CAN2; GPIO_Port = GPIOB; GPIO_Pin = GPIO_PIN_12 | GPIO_PIN_13; + sce_irq = CAN2_SCE_IRQn; __CAN1_CLK_ENABLE(); // CAN2 is a "slave" and needs CAN1 enabled as well __CAN2_CLK_ENABLE(); break; @@ -144,6 +150,14 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { HAL_CAN_Init(&can_obj->can); can_obj->is_enabled = true; + can_obj->num_error_warning = 0; + can_obj->num_error_passive = 0; + can_obj->num_bus_off = 0; + + __HAL_CAN_ENABLE_IT(&can_obj->can, CAN_IT_ERR | CAN_IT_BOF | CAN_IT_EPV | CAN_IT_EWG); + + HAL_NVIC_SetPriority(sce_irq, IRQ_PRI_CAN, IRQ_SUBPRI_CAN); + HAL_NVIC_EnableIRQ(sce_irq); return true; } @@ -459,6 +473,7 @@ STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in) { if (self->can.Instance == CAN1) { HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn); HAL_NVIC_DisableIRQ(CAN1_RX1_IRQn); + HAL_NVIC_DisableIRQ(CAN1_SCE_IRQn); __CAN1_FORCE_RESET(); __CAN1_RELEASE_RESET(); __CAN1_CLK_DISABLE(); @@ -466,6 +481,7 @@ STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in) { } else if (self->can.Instance == CAN2) { HAL_NVIC_DisableIRQ(CAN2_RX0_IRQn); HAL_NVIC_DisableIRQ(CAN2_RX1_IRQn); + HAL_NVIC_DisableIRQ(CAN2_SCE_IRQn); __CAN2_FORCE_RESET(); __CAN2_RELEASE_RESET(); __CAN2_CLK_DISABLE(); @@ -512,6 +528,36 @@ STATIC mp_obj_t pyb_can_state(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_state_obj, pyb_can_state); +// Get info about error states and TX/RX buffers +STATIC mp_obj_t pyb_can_info(size_t n_args, const mp_obj_t *args) { + pyb_can_obj_t *self = MP_OBJ_TO_PTR(args[0]); + mp_obj_list_t *list; + if (n_args == 1) { + list = MP_OBJ_TO_PTR(mp_obj_new_list(8, NULL)); + } else { + if (!MP_OBJ_IS_TYPE(args[1], &mp_type_list)) { + mp_raise_TypeError(NULL); + } + list = MP_OBJ_TO_PTR(args[1]); + if (list->len < 8) { + mp_raise_ValueError(NULL); + } + } + CAN_TypeDef *can = self->can.Instance; + uint32_t esr = can->ESR; + list->items[0] = MP_OBJ_NEW_SMALL_INT(esr >> CAN_ESR_TEC_Pos & 0xff); + list->items[1] = MP_OBJ_NEW_SMALL_INT(esr >> CAN_ESR_REC_Pos & 0xff); + list->items[2] = MP_OBJ_NEW_SMALL_INT(self->num_error_warning); + list->items[3] = MP_OBJ_NEW_SMALL_INT(self->num_error_passive); + list->items[4] = MP_OBJ_NEW_SMALL_INT(self->num_bus_off); + int n_tx_pending = 0x01121223 >> ((can->TSR >> CAN_TSR_TME_Pos & 7) << 2) & 0xf; + list->items[5] = MP_OBJ_NEW_SMALL_INT(n_tx_pending); + list->items[6] = MP_OBJ_NEW_SMALL_INT(can->RF0R >> CAN_RF0R_FMP0_Pos & 3); + list->items[7] = MP_OBJ_NEW_SMALL_INT(can->RF1R >> CAN_RF1R_FMP1_Pos & 3); + return MP_OBJ_FROM_PTR(list); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_can_info_obj, 1, 2, pyb_can_info); + /// \method any(fifo) /// Return `True` if any message waiting on the FIFO, else `False`. STATIC mp_obj_t pyb_can_any(mp_obj_t self_in, mp_obj_t fifo_in) { @@ -871,6 +917,7 @@ STATIC const mp_rom_map_elem_t pyb_can_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_can_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&pyb_can_restart_obj) }, { MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&pyb_can_state_obj) }, + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&pyb_can_info_obj) }, { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&pyb_can_any_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_can_send_obj) }, { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_can_recv_obj) }, @@ -979,6 +1026,21 @@ void can_rx_irq_handler(uint can_id, uint fifo_id) { } } +void can_sce_irq_handler(uint can_id) { + pyb_can_obj_t *self = MP_STATE_PORT(pyb_can_obj_all)[can_id - 1]; + if (self) { + self->can.Instance->MSR = CAN_MSR_ERRI; + uint32_t esr = self->can.Instance->ESR; + if (esr & CAN_ESR_BOFF) { + ++self->num_bus_off; + } else if (esr & CAN_ESR_EPVF) { + ++self->num_error_passive; + } else if (esr & CAN_ESR_EWGF) { + ++self->num_error_warning; + } + } +} + STATIC const mp_stream_p_t can_stream_p = { //.read = can_read, // is read sensible for CAN? //.write = can_write, // is write sensible for CAN? diff --git a/ports/stm32/can.h b/ports/stm32/can.h index b725b59249..54e7deaa5e 100644 --- a/ports/stm32/can.h +++ b/ports/stm32/can.h @@ -34,5 +34,6 @@ extern const mp_obj_type_t pyb_can_type; void can_init0(void); void can_deinit(void); void can_rx_irq_handler(uint can_id, uint fifo_id); +void can_sce_irq_handler(uint can_id); #endif // MICROPY_INCLUDED_STM32_CAN_H diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 0ad71771cb..77cfcc5800 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -749,6 +749,12 @@ void CAN1_RX1_IRQHandler(void) { IRQ_EXIT(CAN1_RX1_IRQn); } +void CAN1_SCE_IRQHandler(void) { + IRQ_ENTER(CAN1_SCE_IRQn); + can_sce_irq_handler(PYB_CAN_1); + IRQ_EXIT(CAN1_SCE_IRQn); +} + void CAN2_RX0_IRQHandler(void) { IRQ_ENTER(CAN2_RX0_IRQn); can_rx_irq_handler(PYB_CAN_2, CAN_FIFO0); @@ -760,6 +766,12 @@ void CAN2_RX1_IRQHandler(void) { can_rx_irq_handler(PYB_CAN_2, CAN_FIFO1); IRQ_EXIT(CAN2_RX1_IRQn); } + +void CAN2_SCE_IRQHandler(void) { + IRQ_ENTER(CAN2_SCE_IRQn); + can_sce_irq_handler(PYB_CAN_2); + IRQ_EXIT(CAN2_SCE_IRQn); +} #endif // MICROPY_HW_ENABLE_CAN #if defined(MICROPY_HW_I2C1_SCL) From b7d576d69a8ef104d4a5538fd09ed97806a15369 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 16 Mar 2018 18:29:43 +1100 Subject: [PATCH 465/828] docs/library/pyb.CAN: Clean up documentation of data constants. --- docs/library/pyb.CAN.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index e1ce90d60d..5fe4c2ecf8 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -259,11 +259,11 @@ Constants --------- .. data:: CAN.NORMAL -.. data:: CAN.LOOPBACK -.. data:: CAN.SILENT -.. data:: CAN.SILENT_LOOPBACK + CAN.LOOPBACK + CAN.SILENT + CAN.SILENT_LOOPBACK - the mode of the CAN bus + The mode of the CAN bus used in :meth:`~CAN.init()`. .. data:: CAN.STOPPED CAN.ERROR_ACTIVE @@ -271,11 +271,11 @@ Constants CAN.ERROR_PASSIVE CAN.BUS_OFF - Possible states of the CAN controller. + Possible states of the CAN controller returned from :meth:`~CAN.state()`. .. data:: CAN.LIST16 -.. data:: CAN.MASK16 -.. data:: CAN.LIST32 -.. data:: CAN.MASK32 + CAN.MASK16 + CAN.LIST32 + CAN.MASK32 - the operation mode of a filter + The operation mode of a filter used in :meth:`~CAN.setfilter()`. From 9600a1f207edf90d72b5f7c545172785f3943ff5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 16 Mar 2018 18:37:55 +1100 Subject: [PATCH 466/828] tests/pyb: Update CAN test to expect that auto_restart is printed. --- tests/pyb/can.py.exp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/pyb/can.py.exp b/tests/pyb/can.py.exp index e25a0f406e..352e5f9690 100644 --- a/tests/pyb/can.py.exp +++ b/tests/pyb/can.py.exp @@ -7,14 +7,14 @@ CAN YA CAN YB ValueError YC CAN(1) -CAN(1, CAN.LOOPBACK, extframe=False) +CAN(1, CAN.LOOPBACK, extframe=False, auto_restart=False) False True (123, False, 0, b'abcd') (2047, False, 0, b'abcd') (0, False, 0, b'abcd') passed -CAN(1, CAN.LOOPBACK, extframe=True) +CAN(1, CAN.LOOPBACK, extframe=True, auto_restart=False) passed ('0x8', '0x1c', '0xa', b'ok') ('0x800', '0x1c00', '0xa00', b'ok') From 06aa13c350af0f3910b2d99303548f31a85c0d9c Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 16 Mar 2018 23:48:29 +1100 Subject: [PATCH 467/828] stm32/can: Use explicit byte extraction instead of casting to word ptr. Casting the Data array to a uint32_t* leads to strict aliasing errors on older gcc compilers. --- ports/stm32/can.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ports/stm32/can.c b/ports/stm32/can.c index b1bcd1c3e6..5b5c4ad3f9 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -222,8 +222,16 @@ STATIC int can_receive(CAN_TypeDef *can, int fifo, CanRxMsgTypeDef *msg, uint32_ msg->RTR = box->RIR & 2; msg->DLC = box->RDTR & 0xf; msg->FMI = box->RDTR >> 8 & 0xff; - *(uint32_t*)&msg->Data[0] = box->RDLR; - *(uint32_t*)&msg->Data[4] = box->RDHR; + uint32_t rdlr = box->RDLR; + msg->Data[0] = rdlr; + msg->Data[1] = rdlr >> 8; + msg->Data[2] = rdlr >> 16; + msg->Data[3] = rdlr >> 24; + uint32_t rdhr = box->RDHR; + msg->Data[4] = rdhr; + msg->Data[5] = rdhr >> 8; + msg->Data[6] = rdhr >> 16; + msg->Data[7] = rdhr >> 24; // Release (free) message from FIFO *rfr |= CAN_RF0R_RFOM0; From f6a1f18603de5c4d2321bcf4f967df298850e3f6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 16 Mar 2018 23:54:06 +1100 Subject: [PATCH 468/828] py/makeqstrdefs.py: Optimise by using compiled re's so it runs faster. By using pre-compiled regexs, using startswith(), and explicitly checking for empty lines (of which around 30% of the input lines are), automatic qstr extraction is speed up by about 10%. --- py/makeqstrdefs.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/py/makeqstrdefs.py b/py/makeqstrdefs.py index 525dec1973..176440136d 100644 --- a/py/makeqstrdefs.py +++ b/py/makeqstrdefs.py @@ -24,12 +24,16 @@ def write_out(fname, output): f.write("\n".join(output) + "\n") def process_file(f): + re_line = re.compile(r"#[line]*\s\d+\s\"([^\"]+)\"") + re_qstr = re.compile(r'MP_QSTR_[_a-zA-Z0-9]+') output = [] last_fname = None for line in f: + if line.isspace(): + continue # match gcc-like output (# n "file") and msvc-like output (#line n "file") - if line and (line[0:2] == "# " or line[0:5] == "#line"): - m = re.match(r"#[line]*\s\d+\s\"([^\"]+)\"", line) + if line.startswith(('# ', '#line')): + m = re_line.match(line) assert m is not None fname = m.group(1) if not fname.endswith(".c"): @@ -39,7 +43,7 @@ def process_file(f): output = [] last_fname = fname continue - for match in re.findall(r'MP_QSTR_[_a-zA-Z0-9]+', line): + for match in re_qstr.findall(line): name = match.replace('MP_QSTR_', '') if name not in QSTRING_BLACK_LIST: output.append('Q(' + name + ')') From 5edce4539b239eab9b045bb2fde18456f6fdbfe4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 17 Mar 2018 00:31:40 +1100 Subject: [PATCH 469/828] py/objexcept: Make MP_DEFINE_EXCEPTION public so ports can define excs. --- py/objexcept.c | 16 +++------------- py/objexcept.h | 13 +++++++++++++ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/py/objexcept.c b/py/objexcept.c index ccb0bad0dd..1e746bc81c 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -93,7 +93,7 @@ mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in) { // definition module-private so far, have it here. const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, 0, 0, NULL, (mp_obj_tuple_t*)&mp_const_empty_tuple_obj}; -STATIC void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { +void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_exception_t *o = MP_OBJ_TO_PTR(o_in); mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS; bool is_subclass = kind & PRINT_EXC_SUBCLASS; @@ -186,7 +186,7 @@ mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in) { } } -STATIC void exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { +void mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in); if (dest[0] != MP_OBJ_NULL) { // store/delete attribute @@ -214,17 +214,7 @@ const mp_obj_type_t mp_type_BaseException = { .name = MP_QSTR_BaseException, .print = mp_obj_exception_print, .make_new = mp_obj_exception_make_new, - .attr = exception_attr, -}; - -#define MP_DEFINE_EXCEPTION(exc_name, base_name) \ -const mp_obj_type_t mp_type_ ## exc_name = { \ - { &mp_type_type }, \ - .name = MP_QSTR_ ## exc_name, \ - .print = mp_obj_exception_print, \ - .make_new = mp_obj_exception_make_new, \ - .attr = exception_attr, \ - .parent = &mp_type_ ## base_name, \ + .attr = mp_obj_exception_attr, }; // List of all exceptions, arranged as in the table at: diff --git a/py/objexcept.h b/py/objexcept.h index f67651a7eb..7c30762248 100644 --- a/py/objexcept.h +++ b/py/objexcept.h @@ -37,4 +37,17 @@ typedef struct _mp_obj_exception_t { mp_obj_tuple_t *args; } mp_obj_exception_t; +void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind); +void mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest); + +#define MP_DEFINE_EXCEPTION(exc_name, base_name) \ +const mp_obj_type_t mp_type_ ## exc_name = { \ + { &mp_type_type }, \ + .name = MP_QSTR_ ## exc_name, \ + .print = mp_obj_exception_print, \ + .make_new = mp_obj_exception_make_new, \ + .attr = mp_obj_exception_attr, \ + .parent = &mp_type_ ## base_name, \ +}; + #endif // MICROPY_INCLUDED_PY_OBJEXCEPT_H From e37b8ba5a55c99dbd1e69eb1c99651307b22fd3e Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 17 Mar 2018 10:42:50 +1100 Subject: [PATCH 470/828] stm32: Use STM32xx macros instead of MCU_SERIES_xx to select MCU type. The CMSIS files for the STM32 range provide macros to distinguish between the different MCU series: STM32F4, STM32F7, STM32H7, STM32L4, etc. Prefer to use these instead of custom ones. --- ports/stm32/Makefile | 6 ++--- ports/stm32/adc.c | 44 +++++++++++++++---------------- ports/stm32/boards/make-pins.py | 2 +- ports/stm32/dac.c | 4 +-- ports/stm32/dma.c | 46 ++++++++++++++++----------------- ports/stm32/dma.h | 4 +-- ports/stm32/extint.c | 12 ++++----- ports/stm32/extint.h | 2 +- ports/stm32/flash.c | 14 +++++----- ports/stm32/i2c.c | 8 +++--- ports/stm32/machine_i2c.c | 2 +- ports/stm32/main.c | 2 +- ports/stm32/modmachine.c | 24 ++++++++--------- ports/stm32/rtc.c | 14 +++++----- ports/stm32/sdcard.c | 6 ++--- ports/stm32/stm32_it.c | 10 +++---- ports/stm32/system_stm32.c | 38 +++++++++++++-------------- ports/stm32/timer.c | 8 +++--- ports/stm32/uart.c | 10 +++---- ports/stm32/usbd_conf.c | 4 +-- 20 files changed, 130 insertions(+), 130 deletions(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 765c55a352..ba4c90dabe 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -61,9 +61,9 @@ CFLAGS_CORTEX_M += -mfpu=fpv4-sp-d16 -mfloat-abi=hard endif # Options for particular MCU series -CFLAGS_MCU_f4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 -DMCU_SERIES_F4 -CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 -DMCU_SERIES_F7 -CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 -DMCU_SERIES_L4 +CFLAGS_MCU_f4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 +CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 +CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 CFLAGS_MCU_h7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_EXTRA) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index ffa16c2f93..781c9aed37 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -56,7 +56,7 @@ #define ADCx_CLK_ENABLE __HAL_RCC_ADC1_CLK_ENABLE #define ADC_NUM_CHANNELS (19) -#if defined(MCU_SERIES_F4) +#if defined(STM32F4) #define ADC_FIRST_GPIO_CHANNEL (0) #define ADC_LAST_GPIO_CHANNEL (15) @@ -64,7 +64,7 @@ #define ADC_CAL1 ((uint16_t*)(ADC_CAL_ADDRESS + 2)) #define ADC_CAL2 ((uint16_t*)(ADC_CAL_ADDRESS + 4)) -#elif defined(MCU_SERIES_F7) +#elif defined(STM32F7) #define ADC_FIRST_GPIO_CHANNEL (0) #define ADC_LAST_GPIO_CHANNEL (15) @@ -78,7 +78,7 @@ #define ADC_CAL1 ((uint16_t*)(ADC_CAL_ADDRESS + 2)) #define ADC_CAL2 ((uint16_t*)(ADC_CAL_ADDRESS + 4)) -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) #define ADC_FIRST_GPIO_CHANNEL (1) #define ADC_LAST_GPIO_CHANNEL (16) @@ -127,7 +127,7 @@ typedef struct _pyb_obj_adc_t { // convert user-facing channel number into internal channel number static inline uint32_t adc_get_internal_channel(uint32_t channel) { - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) // on F4 and F7 MCUs we want channel 16 to always be the TEMPSENSOR // (on some MCUs ADC_CHANNEL_TEMPSENSOR=16, on others it doesn't) if (channel == 16) { @@ -138,9 +138,9 @@ static inline uint32_t adc_get_internal_channel(uint32_t channel) { } STATIC bool is_adcx_channel(int channel) { -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) return IS_ADC_CHANNEL(channel); -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) ADC_HandleTypeDef handle; handle.Instance = ADCx; return IS_ADC_CHANNEL(&handle, channel); @@ -151,9 +151,9 @@ STATIC bool is_adcx_channel(int channel) { STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) { uint32_t tickstart = HAL_GetTick(); -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) while ((ADCx->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC) { -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) while (READ_BIT(ADCx->ISR, ADC_FLAG_EOC) != ADC_FLAG_EOC) { #else #error Unsupported processor @@ -165,9 +165,9 @@ STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) { } STATIC void adcx_clock_enable(void) { -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) ADCx_CLK_ENABLE(); -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) __HAL_RCC_ADC_CLK_ENABLE(); #else #error Unsupported processor @@ -186,9 +186,9 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { mp_hal_gpio_clock_enable(pin->gpio); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Pin = pin->pin_mask; -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) GPIO_InitStructure.Mode = GPIO_MODE_ANALOG; -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) GPIO_InitStructure.Mode = GPIO_MODE_ANALOG_ADC_CONTROL; #else #error Unsupported processor @@ -209,12 +209,12 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { adcHandle->Init.NbrOfConversion = 1; adcHandle->Init.DMAContinuousRequests = DISABLE; adcHandle->Init.Resolution = ADC_RESOLUTION_12B; -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) adcHandle->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; adcHandle->Init.ScanConvMode = DISABLE; adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1; adcHandle->Init.EOCSelection = DISABLE; -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) adcHandle->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; adcHandle->Init.ScanConvMode = ADC_SCAN_DISABLE; adcHandle->Init.EOCSelection = ADC_EOC_SINGLE_CONV; @@ -229,7 +229,7 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { HAL_ADC_Init(adcHandle); -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) ADC_MultiModeTypeDef multimode; multimode.Mode = ADC_MODE_INDEPENDENT; if (HAL_ADCEx_MultiModeConfigChannel(adcHandle, &multimode) != HAL_OK) @@ -244,9 +244,9 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) sConfig.Channel = channel; sConfig.Rank = 1; -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES; -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5; sConfig.SingleDiff = ADC_SINGLE_ENDED; sConfig.OffsetNumber = ADC_OFFSET_NONE; @@ -411,9 +411,9 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_ HAL_ADC_Start(&self->handle); } else { // for subsequent samples we can just set the "start sample" bit -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART; -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) SET_BIT(ADCx->CR, ADC_CR_ADSTART); #else #error Unsupported processor @@ -513,11 +513,11 @@ void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_m adcHandle->Init.NbrOfConversion = 1; adcHandle->Init.DMAContinuousRequests = DISABLE; adcHandle->Init.EOCSelection = DISABLE; -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) adcHandle->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; adcHandle->Init.ScanConvMode = DISABLE; adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1; -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) adcHandle->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2; adcHandle->Init.ScanConvMode = ADC_SCAN_DISABLE; adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIG_T1_CC1; @@ -578,7 +578,7 @@ float adc_read_core_vbat(ADC_HandleTypeDef *adcHandle) { // be 12-bits. raw_value <<= (12 - adc_get_resolution(adcHandle)); - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) // ST docs say that (at least on STM32F42x and STM32F43x), VBATE must // be disabled when TSVREFE is enabled for TEMPSENSOR and VREFINT // conversions to work. VBATE is enabled by the above call to read diff --git a/ports/stm32/boards/make-pins.py b/ports/stm32/boards/make-pins.py index 210c7b63c8..7db174114a 100755 --- a/ports/stm32/boards/make-pins.py +++ b/ports/stm32/boards/make-pins.py @@ -305,7 +305,7 @@ class Pins(object): print('const pin_obj_t * const pin_adc{:d}[] = {{'.format(adc_num)) for channel in range(17): if channel == 16: - print('#if defined(MCU_SERIES_L4)') + print('#if defined(STM32L4)') adc_found = False for named_pin in self.cpu_pins: pin = named_pin.pin() diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c index 268b1bcfb6..9db61964ce 100644 --- a/ports/stm32/dac.c +++ b/ports/stm32/dac.c @@ -159,9 +159,9 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); // DAC peripheral clock - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) __DAC_CLK_ENABLE(); - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) __HAL_RCC_DAC1_CLK_ENABLE(); #else #error Unsupported Processor diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index 5192efa875..137f4bf428 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -53,9 +53,9 @@ typedef enum { } dma_id_t; typedef struct _dma_descr_t { - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) || defined(STM32H7) + #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) DMA_Stream_TypeDef *instance; - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) DMA_Channel_TypeDef *instance; #else #error "Unsupported Processor" @@ -69,9 +69,9 @@ typedef struct _dma_descr_t { // Default parameters to dma_init() shared by spi and i2c; Channel and Direction // vary depending on the peripheral instance so they get passed separately static const DMA_InitTypeDef dma_init_struct_spi_i2c = { - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) .Channel = 0, - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) .Request = 0, #endif .Direction = 0, @@ -81,7 +81,7 @@ static const DMA_InitTypeDef dma_init_struct_spi_i2c = { .MemDataAlignment = DMA_MDATAALIGN_BYTE, .Mode = DMA_NORMAL, .Priority = DMA_PRIORITY_LOW, - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) .FIFOMode = DMA_FIFOMODE_DISABLE, .FIFOThreshold = DMA_FIFO_THRESHOLD_FULL, .MemBurst = DMA_MBURST_INC4, @@ -92,9 +92,9 @@ static const DMA_InitTypeDef dma_init_struct_spi_i2c = { #if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD // Parameters to dma_init() for SDIO tx and rx. static const DMA_InitTypeDef dma_init_struct_sdio = { - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) .Channel = 0, - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) .Request = 0, #endif .Direction = 0, @@ -102,13 +102,13 @@ static const DMA_InitTypeDef dma_init_struct_sdio = { .MemInc = DMA_MINC_ENABLE, .PeriphDataAlignment = DMA_PDATAALIGN_WORD, .MemDataAlignment = DMA_MDATAALIGN_WORD, - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) .Mode = DMA_PFCTRL, - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) .Mode = DMA_NORMAL, #endif .Priority = DMA_PRIORITY_VERY_HIGH, - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) .FIFOMode = DMA_FIFOMODE_ENABLE, .FIFOThreshold = DMA_FIFO_THRESHOLD_FULL, .MemBurst = DMA_MBURST_INC4, @@ -120,9 +120,9 @@ static const DMA_InitTypeDef dma_init_struct_sdio = { #if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC // Default parameters to dma_init() for DAC tx static const DMA_InitTypeDef dma_init_struct_dac = { - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) .Channel = 0, - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) .Request = 0, #endif .Direction = 0, @@ -132,7 +132,7 @@ static const DMA_InitTypeDef dma_init_struct_dac = { .MemDataAlignment = DMA_MDATAALIGN_BYTE, .Mode = DMA_NORMAL, .Priority = DMA_PRIORITY_HIGH, - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) .FIFOMode = DMA_FIFOMODE_DISABLE, .FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL, .MemBurst = DMA_MBURST_SINGLE, @@ -141,7 +141,7 @@ static const DMA_InitTypeDef dma_init_struct_dac = { }; #endif -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) #define NCONTROLLERS (2) #define NSTREAMS_PER_CONTROLLER (8) @@ -161,7 +161,7 @@ static const DMA_InitTypeDef dma_init_struct_dac = { // DMA1 streams const dma_descr_t dma_I2C_1_RX = { DMA1_Stream0, DMA_CHANNEL_1, DMA_PERIPH_TO_MEMORY, dma_id_0, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_3_RX = { DMA1_Stream2, DMA_CHANNEL_0, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c }; -#if defined(MCU_SERIES_F7) +#if defined(STM32F7) const dma_descr_t dma_I2C_4_RX = { DMA1_Stream2, DMA_CHANNEL_2, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c }; #endif const dma_descr_t dma_I2C_3_RX = { DMA1_Stream2, DMA_CHANNEL_3, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c }; @@ -169,7 +169,7 @@ const dma_descr_t dma_I2C_2_RX = { DMA1_Stream2, DMA_CHANNEL_7, DMA_PERIPH_TO_ME const dma_descr_t dma_SPI_2_RX = { DMA1_Stream3, DMA_CHANNEL_0, DMA_PERIPH_TO_MEMORY, dma_id_3, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_2_TX = { DMA1_Stream4, DMA_CHANNEL_0, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c }; const dma_descr_t dma_I2C_3_TX = { DMA1_Stream4, DMA_CHANNEL_3, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c }; -#if defined(MCU_SERIES_F7) +#if defined(STM32F7) const dma_descr_t dma_I2C_4_TX = { DMA1_Stream5, DMA_CHANNEL_2, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_spi_i2c }; #endif #if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC @@ -185,7 +185,7 @@ const dma_descr_t dma_I2C_1_TX = { DMA1_Stream6, DMA_CHANNEL_1, DMA_MEMORY_TO_PE */ // DMA2 streams -#if defined(MCU_SERIES_F7) && defined(SDMMC2) && MICROPY_HW_HAS_SDCARD +#if defined(STM32F7) && defined(SDMMC2) && MICROPY_HW_HAS_SDCARD const dma_descr_t dma_SDMMC_2_RX= { DMA2_Stream0, DMA_CHANNEL_11, DMA_PERIPH_TO_MEMORY, dma_id_8, &dma_init_struct_sdio }; #endif const dma_descr_t dma_SPI_1_RX = { DMA2_Stream2, DMA_CHANNEL_3, DMA_PERIPH_TO_MEMORY, dma_id_10, &dma_init_struct_spi_i2c }; @@ -198,7 +198,7 @@ const dma_descr_t dma_SPI_5_TX = { DMA2_Stream4, DMA_CHANNEL_2, DMA_MEMORY_TO_PE const dma_descr_t dma_SPI_4_TX = { DMA2_Stream4, DMA_CHANNEL_5, DMA_MEMORY_TO_PERIPH, dma_id_12, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_6_TX = { DMA2_Stream5, DMA_CHANNEL_1, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_1_TX = { DMA2_Stream5, DMA_CHANNEL_3, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_spi_i2c }; -#if defined(MCU_SERIES_F7) && defined(SDMMC2) && MICROPY_HW_HAS_SDCARD +#if defined(STM32F7) && defined(SDMMC2) && MICROPY_HW_HAS_SDCARD const dma_descr_t dma_SDMMC_2_TX= { DMA2_Stream5, DMA_CHANNEL_11, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_sdio }; #endif const dma_descr_t dma_SPI_6_RX = { DMA2_Stream6, DMA_CHANNEL_1, DMA_PERIPH_TO_MEMORY, dma_id_14, &dma_init_struct_spi_i2c }; @@ -233,7 +233,7 @@ static const uint8_t dma_irqn[NSTREAM] = { DMA2_Stream7_IRQn, }; -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) #define NCONTROLLERS (2) #define NSTREAMS_PER_CONTROLLER (7) @@ -396,7 +396,7 @@ volatile dma_idle_count_t dma_idle; #define DMA1_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA1EN) != 0) #define DMA2_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA2EN) != 0) -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) || defined(STM32H7) +#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) void DMA1_Stream0_IRQHandler(void) { IRQ_ENTER(DMA1_Stream0_IRQn); if (dma_handle[dma_id_0] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_0]); } IRQ_EXIT(DMA1_Stream0_IRQn); } void DMA1_Stream1_IRQHandler(void) { IRQ_ENTER(DMA1_Stream1_IRQn); if (dma_handle[dma_id_1] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_1]); } IRQ_EXIT(DMA1_Stream1_IRQn); } @@ -415,7 +415,7 @@ void DMA2_Stream5_IRQHandler(void) { IRQ_ENTER(DMA2_Stream5_IRQn); if (dma_handl void DMA2_Stream6_IRQHandler(void) { IRQ_ENTER(DMA2_Stream6_IRQn); if (dma_handle[dma_id_14] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_14]); } IRQ_EXIT(DMA2_Stream6_IRQn); } void DMA2_Stream7_IRQHandler(void) { IRQ_ENTER(DMA2_Stream7_IRQn); if (dma_handle[dma_id_15] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_15]); } IRQ_EXIT(DMA2_Stream7_IRQn); } -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) void DMA1_Channel1_IRQHandler(void) { IRQ_ENTER(DMA1_Channel1_IRQn); if (dma_handle[dma_id_0] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_0]); } IRQ_EXIT(DMA1_Channel1_IRQn); } void DMA1_Channel2_IRQHandler(void) { IRQ_ENTER(DMA1_Channel2_IRQn); if (dma_handle[dma_id_1] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_1]); } IRQ_EXIT(DMA1_Channel2_IRQn); } @@ -485,7 +485,7 @@ void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void dma->Instance = dma_descr->instance; dma->Init = *dma_descr->init; dma->Init.Direction = dma_descr->transfer_direction; - #if defined(MCU_SERIES_L4) || defined(STM32H7) + #if defined(STM32L4) || defined(STM32H7) dma->Init.Request = dma_descr->sub_instance; #else dma->Init.Channel = dma_descr->sub_instance; @@ -524,7 +524,7 @@ void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void *data){ } else { // only necessary initialization dma->State = HAL_DMA_STATE_READY; -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) // calculate DMA base address and bitshift to be used in IRQ handler extern uint32_t DMA_CalcBaseAndBitshift(DMA_HandleTypeDef *hdma); DMA_CalcBaseAndBitshift(dma); diff --git a/ports/stm32/dma.h b/ports/stm32/dma.h index 0055181612..15a424a358 100644 --- a/ports/stm32/dma.h +++ b/ports/stm32/dma.h @@ -28,7 +28,7 @@ typedef struct _dma_descr_t dma_descr_t; -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) extern const dma_descr_t dma_I2C_1_RX; extern const dma_descr_t dma_SPI_3_RX; @@ -57,7 +57,7 @@ extern const dma_descr_t dma_SDMMC_2_TX; extern const dma_descr_t dma_SPI_6_RX; extern const dma_descr_t dma_SDIO_0_TX; -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) extern const dma_descr_t dma_ADC_1_RX; extern const dma_descr_t dma_ADC_2_RX; diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c index be4d20bb4d..9fe53a1a3c 100644 --- a/ports/stm32/extint.c +++ b/ports/stm32/extint.c @@ -89,7 +89,7 @@ // register in an atomic fashion by using bitband addressing. #define EXTI_MODE_BB(mode, line) (*(__IO uint32_t *)(PERIPH_BB_BASE + ((EXTI_OFFSET + (mode)) * 32) + ((line) * 4))) -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) // The L4 MCU supports 40 Events/IRQs lines of the type configurable and direct. // Here we only support configurable line types. Details, see page 330 of RM0351, Rev 1. // The USB_FS_WAKUP event is a direct type and there is no support for it. @@ -137,7 +137,7 @@ STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = { EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) PVD_PVM_IRQn, #else PVD_IRQn, @@ -282,7 +282,7 @@ void extint_enable(uint line) { if (line >= EXTI_NUM_VECTORS) { return; } - #if defined(MCU_SERIES_F7) || defined(STM32H7) + #if defined(STM32F7) || defined(STM32H7) // The Cortex-M7 doesn't have bitband support. mp_uint_t irq_state = disable_irq(); if (pyb_extint_mode[line] == EXTI_Mode_Interrupt) { @@ -312,7 +312,7 @@ void extint_disable(uint line) { return; } - #if defined(MCU_SERIES_F7) || defined(STM32H7) + #if defined(STM32F7) || defined(STM32H7) // The Cortex-M7 doesn't have bitband support. mp_uint_t irq_state = disable_irq(); #if defined(STM32H7) @@ -337,7 +337,7 @@ void extint_swint(uint line) { return; } // we need 0 to 1 transition to trigger the interrupt -#if defined(MCU_SERIES_L4) || defined(STM32H7) +#if defined(STM32L4) || defined(STM32H7) EXTI->SWIER1 &= ~(1 << line); EXTI->SWIER1 |= (1 << line); #else @@ -386,7 +386,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_swint_obj, extint_obj_swint); /// \classmethod regs() /// Dump the values of the EXTI registers. STATIC mp_obj_t extint_regs(void) { - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) printf("EXTI_IMR1 %08lx\n", EXTI->IMR1); printf("EXTI_IMR2 %08lx\n", EXTI->IMR2); printf("EXTI_EMR1 %08lx\n", EXTI->EMR1); diff --git a/ports/stm32/extint.h b/ports/stm32/extint.h index 0bd20affa7..c4a4ae6bb9 100644 --- a/ports/stm32/extint.h +++ b/ports/stm32/extint.h @@ -38,7 +38,7 @@ #define EXTI_USB_OTG_HS_WAKEUP (20) #define EXTI_RTC_TIMESTAMP (21) #define EXTI_RTC_WAKEUP (22) -#if defined(MCU_SERIES_F7) +#if defined(STM32F7) #define EXTI_LPTIM1_ASYNC_EVENT (23) #endif diff --git a/ports/stm32/flash.c b/ports/stm32/flash.c index 4042785fa2..214d10fdb0 100644 --- a/ports/stm32/flash.c +++ b/ports/stm32/flash.c @@ -34,7 +34,7 @@ typedef struct { uint32_t sector_count; } flash_layout_t; -#if defined(MCU_SERIES_F4) +#if defined(STM32F4) static const flash_layout_t flash_layout[] = { { 0x08000000, 0x04000, 4 }, @@ -50,7 +50,7 @@ static const flash_layout_t flash_layout[] = { #endif }; -#elif defined(MCU_SERIES_F7) +#elif defined(STM32F7) // FLASH_FLAG_PGSERR (Programming Sequence Error) was renamed to // FLASH_FLAG_ERSERR (Erasing Sequence Error) in STM32F7 @@ -62,7 +62,7 @@ static const flash_layout_t flash_layout[] = { { 0x08040000, 0x40000, 3 }, }; -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) static const flash_layout_t flash_layout[] = { { (uint32_t)FLASH_BASE, (uint32_t)FLASH_PAGE_SIZE, 512 }, @@ -78,7 +78,7 @@ static const flash_layout_t flash_layout[] = { #error Unsupported processor #endif -#if defined(MCU_SERIES_L4) || defined(STM32H7) +#if defined(STM32L4) || defined(STM32H7) // get the bank of a given flash address static uint32_t get_bank(uint32_t addr) { @@ -103,7 +103,7 @@ static uint32_t get_bank(uint32_t addr) { } } -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) // get the page of a given flash address static uint32_t get_page(uint32_t addr) { if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) { @@ -153,7 +153,7 @@ void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) FLASH_EraseInitTypeDef EraseInitStruct; - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS); // erase the sector(s) @@ -220,7 +220,7 @@ void flash_erase_it(uint32_t flash_dest, const uint32_t *src, uint32_t num_word3 */ void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) { - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) // program the flash uint64 by uint64 for (int i = 0; i < num_word32 / 2; i++) { diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index b9ab16e123..f072a75b8f 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -131,7 +131,7 @@ const pyb_i2c_obj_t pyb_i2c_obj[] = { #endif }; -#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) +#if defined(STM32F7) || defined(STM32L4) // The STM32F0, F3, F7 and L4 use a TIMINGR register rather than ClockSpeed and // DutyCycle. @@ -161,7 +161,7 @@ const pyb_i2c_obj_t pyb_i2c_obj[] = { #define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL) #define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FAST) -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) // The value 0x90112626 was obtained from the DISCOVERY_I2C1_TIMING constant // defined in the STM32L4Cube file Drivers/BSP/STM32L476G-Discovery/stm32l476g_discovery.h @@ -424,7 +424,7 @@ void i2c_ev_irq_handler(mp_uint_t i2c_id) { return; } - #if defined(MCU_SERIES_F4) + #if defined(STM32F4) if (hi2c->Instance->SR1 & I2C_FLAG_BTF && hi2c->State == HAL_I2C_STATE_BUSY_TX) { if (hi2c->XferCount != 0U) { @@ -476,7 +476,7 @@ void i2c_er_irq_handler(mp_uint_t i2c_id) { return; } - #if defined(MCU_SERIES_F4) + #if defined(STM32F4) uint32_t sr1 = hi2c->Instance->SR1; diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c index 5822b8e672..2844469ddf 100644 --- a/ports/stm32/machine_i2c.c +++ b/ports/stm32/machine_i2c.c @@ -38,7 +38,7 @@ STATIC const mp_obj_type_t machine_hard_i2c_type; -#if defined(MCU_SERIES_F4) +#if defined(STM32F4) // F4xx specific driver for I2C hardware peripheral // The hardware-specific I2C code below is based heavily on the code from diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 5fd2787e09..ccf490e36b 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -433,7 +433,7 @@ int main(void) { __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) #if defined(__HAL_RCC_DTCMRAMEN_CLK_ENABLE) // The STM32F746 doesn't really have CCM memory, but it does have DTCM, // which behaves more or less like normal SRAM. diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index 8b2c4e2f61..02a6f2a4b9 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -54,7 +54,7 @@ #include "wdt.h" #include "genhdr/pllfreqtable.h" -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) // L4 does not have a POR, so use BOR instead #define RCC_CSR_PORRSTF RCC_CSR_BORRSTF #endif @@ -86,13 +86,13 @@ STATIC uint32_t reset_cause; void machine_init(void) { - #if defined(MCU_SERIES_F4) + #if defined(STM32F4) if (PWR->CSR & PWR_CSR_SBF) { // came out of standby reset_cause = PYB_RESET_DEEPSLEEP; PWR->CR |= PWR_CR_CSBF; } else - #elif defined(MCU_SERIES_F7) + #elif defined(STM32F7) if (PWR->CSR1 & PWR_CSR1_SBF) { // came out of standby reset_cause = PYB_RESET_DEEPSLEEP; @@ -241,7 +241,7 @@ STATIC NORETURN mp_obj_t machine_bootloader(void) { HAL_MPU_Disable(); #endif -#if defined(MCU_SERIES_F7) || defined(STM32H7) +#if defined(STM32F7) || defined(STM32H7) // arm-none-eabi-gcc 4.9.0 does not correctly inline this // MSP function, so we write it out explicitly here. //__set_MSP(*((uint32_t*) 0x1FF00000)); @@ -296,7 +296,7 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { // set mp_int_t wanted_sysclk = mp_obj_get_int(args[0]) / 1000000; - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) mp_raise_NotImplementedError("machine.freq set not supported yet"); #endif @@ -391,7 +391,7 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { // set PLL as system clock source if wanted if (sysclk_source == RCC_SYSCLKSOURCE_PLLCLK) { uint32_t flash_latency; - #if defined(MCU_SERIES_F7) + #if defined(STM32F7) // if possible, scale down the internal voltage regulator to save power // the flash_latency values assume a supply voltage between 2.7V and 3.6V uint32_t volt_scale; @@ -419,7 +419,7 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { } #endif - #if !defined(MCU_SERIES_F7) + #if !defined(STM32F7) #if !defined(MICROPY_HW_FLASH_LATENCY) #define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_5 #endif @@ -433,7 +433,7 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { } #if defined(MICROPY_HW_CLK_LAST_FREQ) && MICROPY_HW_CLK_LAST_FREQ - #if defined(MCU_SERIES_F7) + #if defined(STM32F7) #define FREQ_BKP BKP31R #else #define FREQ_BKP BKP19R @@ -459,7 +459,7 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 4, machine_freq); STATIC mp_obj_t machine_sleep(void) { - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) // Enter Stop 1 mode __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI); @@ -491,7 +491,7 @@ STATIC mp_obj_t machine_sleep(void) { // takes longer to wake but reduces stop current HAL_PWREx_EnableFlashPowerDown(); - # if defined(MCU_SERIES_F7) + # if defined(STM32F7) HAL_PWR_EnterSTOPMode((PWR_CR1_LPDS | PWR_CR1_LPUDS | PWR_CR1_FPDS | PWR_CR1_UDEN), PWR_STOPENTRY_WFI); # else HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); @@ -527,7 +527,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep); STATIC mp_obj_t machine_deepsleep(void) { rtc_init_finalise(); -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) printf("machine.deepsleep not supported yet\n"); #else // We need to clear the PWR wake-up-flag before entering standby, since @@ -549,7 +549,7 @@ STATIC mp_obj_t machine_deepsleep(void) { // clear RTC wake-up flags RTC->ISR &= ~(RTC_ISR_ALRAF | RTC_ISR_ALRBF | RTC_ISR_WUTF | RTC_ISR_TSF); - #if defined(MCU_SERIES_F7) + #if defined(STM32F7) // disable wake-up flags PWR->CSR2 &= ~(PWR_CSR2_EWUP6 | PWR_CSR2_EWUP5 | PWR_CSR2_EWUP4 | PWR_CSR2_EWUP3 | PWR_CSR2_EWUP2 | PWR_CSR2_EWUP1); // clear global wake-up flag diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index 7e67b7c622..8fb6ae29fc 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -191,7 +191,7 @@ void rtc_init_finalise() { // fresh reset; configure RTC Calendar RTC_CalendarConfig(); - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) if(__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST) != RESET) { #else if(__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST) != RESET) { @@ -232,7 +232,7 @@ STATIC HAL_StatusTypeDef PYB_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruc HAL_PWR_EnableBkUpAccess(); uint32_t tickstart = HAL_GetTick(); - #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) || defined(STM32H7) + #if defined(STM32F7) || defined(STM32L4) || defined(STM32H7) //__HAL_RCC_PWR_CLK_ENABLE(); // Enable write access to Backup domain //PWR->CR1 |= PWR_CR1_DBP; @@ -302,10 +302,10 @@ STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc) { // Exit Initialization mode hrtc->Instance->ISR &= (uint32_t)~RTC_ISR_INIT; - #if defined(MCU_SERIES_L4) || defined(STM32H7) + #if defined(STM32L4) || defined(STM32H7) hrtc->Instance->OR &= (uint32_t)~RTC_OR_ALARMOUTTYPE; hrtc->Instance->OR |= (uint32_t)(hrtc->Init.OutPutType); - #elif defined(MCU_SERIES_F7) + #elif defined(STM32F7) hrtc->Instance->OR &= (uint32_t)~RTC_OR_ALARMTYPE; hrtc->Instance->OR |= (uint32_t)(hrtc->Init.OutPutType); #else @@ -635,7 +635,7 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) { RTC->WPR = 0xff; // enable external interrupts on line 22 - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) EXTI->IMR1 |= 1 << 22; EXTI->RTSR1 |= 1 << 22; #elif defined(STM32H7) @@ -648,7 +648,7 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) { // clear interrupt flags RTC->ISR &= ~(1 << 10); - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) EXTI->PR1 = 1 << 22; #elif defined(STM32H7) EXTI_D1->PR1 = 1 << 22; @@ -668,7 +668,7 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) { RTC->WPR = 0xff; // disable external interrupts on line 22 - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) EXTI->IMR1 &= ~(1 << 22); #elif defined(STM32H7) EXTI_D1->IMR1 |= 1 << 22; diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index 9b087ef849..5f13c923e8 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -40,7 +40,7 @@ #if MICROPY_HW_HAS_SDCARD -#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) +#if defined(STM32F7) || defined(STM32L4) // The F7 has 2 SDMMC units but at the moment we only support using one of them in // a given build. If a boards config file defines MICROPY_HW_SDMMC2_CK then SDMMC2 @@ -198,7 +198,7 @@ bool sdcard_power_on(void) { } // configure the SD bus width for wide operation - #if defined(MCU_SERIES_F7) + #if defined(STM32F7) // use maximum SDMMC clock speed on F7 MCUs sd_handle.Init.ClockBypass = SDMMC_CLOCK_BYPASS_ENABLE; #endif @@ -239,7 +239,7 @@ void SDIO_IRQHandler(void) { } #endif -#if defined(MCU_SERIES_F7) +#if defined(STM32F7) void SDMMC2_IRQHandler(void) { IRQ_ENTER(SDMMC2_IRQn); HAL_SD_IRQHandler(&sd_handle); diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 77cfcc5800..987ace69a7 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -522,7 +522,7 @@ void PVD_IRQHandler(void) { IRQ_EXIT(PVD_IRQn); } -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) void PVD_PVM_IRQHandler(void) { IRQ_ENTER(PVD_PVM_IRQn); Handle_EXTI_Irq(EXTI_PVD_OUTPUT); @@ -563,7 +563,7 @@ void TIM1_BRK_TIM9_IRQHandler(void) { IRQ_EXIT(TIM1_BRK_TIM9_IRQn); } -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) void TIM1_BRK_TIM15_IRQHandler(void) { IRQ_ENTER(TIM1_BRK_TIM15_IRQn); timer_irq_handler(15); @@ -578,7 +578,7 @@ void TIM1_UP_TIM10_IRQHandler(void) { IRQ_EXIT(TIM1_UP_TIM10_IRQn); } -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) void TIM1_UP_TIM16_IRQHandler(void) { IRQ_ENTER(TIM1_UP_TIM16_IRQn); timer_irq_handler(1); @@ -593,7 +593,7 @@ void TIM1_TRG_COM_TIM11_IRQHandler(void) { IRQ_EXIT(TIM1_TRG_COM_TIM11_IRQn); } -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) void TIM1_TRG_COM_TIM17_IRQHandler(void) { IRQ_ENTER(TIM1_TRG_COM_TIM17_IRQn); timer_irq_handler(17); @@ -662,7 +662,7 @@ void TIM8_UP_TIM13_IRQHandler(void) { IRQ_EXIT(TIM8_UP_TIM13_IRQn); } -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) void TIM8_UP_IRQHandler(void) { IRQ_ENTER(TIM8_UP_IRQn); timer_irq_handler(8); diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c index 77875f32c3..6c24ee417b 100644 --- a/ports/stm32/system_stm32.c +++ b/ports/stm32/system_stm32.c @@ -107,21 +107,21 @@ void __fatal_error(const char *msg); * @{ */ -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) #define CONFIG_RCC_CR_1ST (RCC_CR_HSION) #define CONFIG_RCC_CR_2ND (RCC_CR_HSEON | RCC_CR_CSSON | RCC_CR_PLLON) #define CONFIG_RCC_PLLCFGR (0x24003010) -#if defined(MCU_SERIES_F4) +#if defined(STM32F4) const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; -#elif defined(MCU_SERIES_F7) +#elif defined(STM32F7) const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; #endif -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) #define CONFIG_RCC_CR_1ST (RCC_CR_MSION) #define CONFIG_RCC_CR_2ND (RCC_CR_HSEON | RCC_CR_CSSON | RCC_CR_HSION | RCC_CR_PLLON) @@ -263,9 +263,9 @@ void SystemInit(void) RCC->CR &= (uint32_t)0xFFFBFFFF; /* Disable all interrupts */ - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) RCC->CIR = 0x00000000; - #elif defined(MCU_SERIES_L4) || defined(STM32H7) + #elif defined(STM32L4) || defined(STM32H7) RCC->CIER = 0x00000000; #endif @@ -373,7 +373,7 @@ void SystemClock_Config(void) RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; #endif - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) || defined(STM32H7) + #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) /* Enable Power Control clock */ #if defined(STM32H7) @@ -386,7 +386,7 @@ void SystemClock_Config(void) clocked below the maximum system frequency, to update the voltage scaling value regarding system frequency refer to product datasheet. */ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) // Configure LSE Drive Capability __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW); #endif @@ -398,7 +398,7 @@ void SystemClock_Config(void) #endif /* Enable HSE Oscillator and activate PLL with HSE as source */ - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) || defined(STM32H7) + #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSIState = RCC_HSI_OFF; @@ -406,7 +406,7 @@ void SystemClock_Config(void) RCC_OscInitStruct.CSIState = RCC_CSI_OFF; #endif RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI; RCC_OscInitStruct.LSEState = RCC_LSE_ON; RCC_OscInitStruct.MSIState = RCC_MSI_ON; @@ -424,9 +424,9 @@ void SystemClock_Config(void) RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; #if defined(MICROPY_HW_CLK_LAST_FREQ) && MICROPY_HW_CLK_LAST_FREQ - #if defined(MCU_SERIES_F7) + #if defined(STM32F7) #define FREQ_BKP BKP31R - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) #error Unsupported Processor #else #define FREQ_BKP BKP19R @@ -470,7 +470,7 @@ void SystemClock_Config(void) RCC_OscInitStruct.PLL.PLLN = MICROPY_HW_CLK_PLLN; RCC_OscInitStruct.PLL.PLLP = MICROPY_HW_CLK_PLLP; RCC_OscInitStruct.PLL.PLLQ = MICROPY_HW_CLK_PLLQ; - #if defined(MCU_SERIES_L4) || defined(STM32H7) + #if defined(STM32L4) || defined(STM32H7) RCC_OscInitStruct.PLL.PLLR = MICROPY_HW_CLK_PLLR; #endif @@ -480,11 +480,11 @@ void SystemClock_Config(void) RCC_OscInitStruct.PLL.PLLFRACN = 0; #endif - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; @@ -519,7 +519,7 @@ void SystemClock_Config(void) } #endif -#if defined(MCU_SERIES_F7) +#if defined(STM32F7) /* Activate the OverDrive to reach the 200 MHz Frequency */ if (HAL_PWREx_EnableOverDrive() != HAL_OK) { @@ -550,14 +550,14 @@ void SystemClock_Config(void) HAL_PWREx_EnableUSBVoltageDetector(); #endif -#if defined(MCU_SERIES_F7) +#if defined(STM32F7) // The DFU bootloader changes the clocksource register from its default power // on reset value, so we set it back here, so the clocksources are the same // whether we were started from DFU or from a power on reset. RCC->DCKCFGR2 = 0; #endif -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) // Enable MSI-Hardware auto calibration mode with LSE HAL_RCCEx_EnableMSIPLLMode(); @@ -600,7 +600,7 @@ void SystemClock_Config(void) } void HAL_MspInit(void) { -#if defined(MCU_SERIES_F7) || defined(STM32H7) +#if defined(STM32F7) || defined(STM32H7) /* Enable I-Cache */ SCB_EnableICache(); diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c index fa6141634b..18661da9c7 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -651,9 +651,9 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons // It assumes that timer instance pointer has the lower 8 bits cleared. #define TIM_ENTRY(id, irq) [id - 1] = (uint32_t)TIM##id | irq STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = { - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) TIM_ENTRY(1, TIM1_UP_TIM10_IRQn), - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) TIM_ENTRY(1, TIM1_UP_TIM16_IRQn), #endif TIM_ENTRY(2, TIM2_IRQn), @@ -671,9 +671,9 @@ STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = { TIM_ENTRY(7, TIM7_IRQn), #endif #if defined(TIM8) - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) TIM_ENTRY(8, TIM8_UP_TIM13_IRQn), - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) TIM_ENTRY(8, TIM8_UP_IRQn), #endif #endif diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index 72bc3bb2f4..2fcbbd74c6 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -383,7 +383,7 @@ int uart_rx_char(pyb_uart_obj_t *self) { return data; } else { // no buffering - #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) || defined(STM32H7) + #if defined(STM32F7) || defined(STM32L4) || defined(STM32H7) return self->uart.Instance->RDR & self->char_mask; #else return self->uart.Instance->DR & self->char_mask; @@ -462,7 +462,7 @@ STATIC size_t uart_tx_data(pyb_uart_obj_t *self, const void *src_in, size_t num_ } else { data = *src++; } - #if defined(MCU_SERIES_F4) + #if defined(STM32F4) uart->DR = data; #else uart->TDR = data; @@ -501,7 +501,7 @@ void uart_irq_handler(mp_uint_t uart_id) { uint16_t next_head = (self->read_buf_head + 1) % self->read_buf_len; if (next_head != self->read_buf_tail) { // only read data if room in buf - #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) || defined(STM32H7) + #if defined(STM32F7) || defined(STM32L4) || defined(STM32H7) int data = self->uart.Instance->RDR; // clears UART_FLAG_RXNE #else int data = self->uart.Instance->DR; // clears UART_FLAG_RXNE @@ -686,7 +686,7 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const // compute actual baudrate that was configured // (this formula assumes UART_OVERSAMPLING_16) uint32_t actual_baudrate = 0; - #if defined(MCU_SERIES_F7) || defined(STM32H7) + #if defined(STM32F7) || defined(STM32H7) UART_ClockSourceTypeDef clocksource = UART_CLOCKSOURCE_UNDEFINED; UART_GETCLOCKSOURCE(&self->uart, clocksource); switch (clocksource) { @@ -937,7 +937,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_readchar_obj, pyb_uart_readchar); // uart.sendbreak() STATIC mp_obj_t pyb_uart_sendbreak(mp_obj_t self_in) { pyb_uart_obj_t *self = self_in; - #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) || defined(STM32H7) + #if defined(STM32F7) || defined(STM32L4) || defined(STM32H7) self->uart.Instance->RQR = USART_RQR_SBKRQ; // write-only register #else self->uart.Instance->CR1 |= USART_CR1_SBK; diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index abc12958e0..fe05e2e4c1 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -102,7 +102,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) /* Enable USB FS Clocks */ __USB_OTG_FS_CLK_ENABLE(); -#if defined (MCU_SERIES_L4) +#if defined(STM32L4) /* Enable VDDUSB */ if(__HAL_RCC_PWR_IS_CLK_DISABLED()) { @@ -432,7 +432,7 @@ if (pdev->id == USB_PHY_FS_ID) pcd_fs_handle.Init.phy_itface = PCD_PHY_EMBEDDED; pcd_fs_handle.Init.Sof_enable = 1; pcd_fs_handle.Init.speed = PCD_SPEED_FULL; -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) pcd_fs_handle.Init.lpm_enable = DISABLE; pcd_fs_handle.Init.battery_charging_enable = DISABLE; #endif From 5e1279d41a4130027c594f087f8539b5b25cc29b Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 9 Mar 2018 11:34:46 +1100 Subject: [PATCH 471/828] travis: Pass -j4 to make to speed up compilation. This seems to reduce the Travis build time by roughly 1 minute / 10%. --- .travis.yml | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/.travis.yml b/.travis.yml index 27e9fac96f..d50a5d2615 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,8 @@ compiler: cache: directories: - "${HOME}/persist" +env: + - MAKEOPTS="-j4" before_script: # Extra CPython versions @@ -26,33 +28,33 @@ before_script: - python3 --version script: - - make -C mpy-cross - - make -C ports/minimal CROSS=1 build/firmware.bin + - make ${MAKEOPTS} -C mpy-cross + - make ${MAKEOPTS} -C ports/minimal CROSS=1 build/firmware.bin - ls -l ports/minimal/build/firmware.bin - tools/check_code_size.sh - mkdir -p ${HOME}/persist # Save new firmware for reference, but only if building a main branch, not a pull request - 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then cp ports/minimal/build/firmware.bin ${HOME}/persist/; fi' - - make -C ports/unix deplibs - - make -C ports/unix - - make -C ports/unix nanbox - - make -C ports/bare-arm - - make -C ports/qemu-arm -f Makefile.test test - - make -C ports/stm32 - - make -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1 - - make -C ports/stm32 BOARD=STM32F769DISC - - make -C ports/stm32 BOARD=STM32L476DISC - - make -C ports/teensy - - make -C ports/cc3200 BTARGET=application BTYPE=release - - make -C ports/cc3200 BTARGET=bootloader BTYPE=release - - make -C ports/windows CROSS_COMPILE=i686-w64-mingw32- + - make ${MAKEOPTS} -C ports/unix deplibs + - make ${MAKEOPTS} -C ports/unix + - make ${MAKEOPTS} -C ports/unix nanbox + - make ${MAKEOPTS} -C ports/bare-arm + - make ${MAKEOPTS} -C ports/qemu-arm -f Makefile.test test + - make ${MAKEOPTS} -C ports/stm32 + - make ${MAKEOPTS} -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1 + - make ${MAKEOPTS} -C ports/stm32 BOARD=STM32F769DISC + - make ${MAKEOPTS} -C ports/stm32 BOARD=STM32L476DISC + - make ${MAKEOPTS} -C ports/teensy + - make ${MAKEOPTS} -C ports/cc3200 BTARGET=application BTYPE=release + - make ${MAKEOPTS} -C ports/cc3200 BTARGET=bootloader BTYPE=release + - make ${MAKEOPTS} -C ports/windows CROSS_COMPILE=i686-w64-mingw32- # run tests without coverage info #- (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests) #- (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests --emit native) # run tests with coverage info - - make -C ports/unix coverage + - make ${MAKEOPTS} -C ports/unix coverage - (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests) - (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests -d thread) - (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --emit native) @@ -66,7 +68,7 @@ script: # run tests on stackless build - rm -rf ports/unix/build-coverage - - make -C ports/unix coverage CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1" + - make ${MAKEOPTS} -C ports/unix coverage CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1" - (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests) after_failure: From 0abbafd42406e4367a80ad996bdd7047ad1e020d Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 19 Mar 2018 15:12:24 +1100 Subject: [PATCH 472/828] stm32/can: Add "list" param to CAN.recv() to receive data inplace. This API matches (as close as possible) how other pyb classes allow inplace operations, such as pyb.SPI.recv(buf). --- docs/library/pyb.CAN.rst | 21 +++++++++++++- ports/stm32/can.c | 62 +++++++++++++++++++++++++++++----------- 2 files changed, 66 insertions(+), 17 deletions(-) diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index 5fe4c2ecf8..09b97a187c 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -187,11 +187,12 @@ Methods Return ``True`` if any message waiting on the FIFO, else ``False``. -.. method:: CAN.recv(fifo, \*, timeout=5000) +.. method:: CAN.recv(fifo, list=None, \*, timeout=5000) Receive data on the bus: - *fifo* is an integer, which is the FIFO to receive on + - *list* is an optional list object to be used as the return value - *timeout* is the timeout in milliseconds to wait for the receive. Return value: A tuple containing four values. @@ -201,6 +202,24 @@ Methods - The FMI (Filter Match Index) value. - An array containing the data. + If *list* is ``None`` then a new tuple will be allocated, as well as a new + bytes object to contain the data (as the fourth element in the tuple). + + If *list* is not ``None`` then it should be a list object with a least four + elements. The fourth element should be a memoryview object which is created + from either a bytearray or an array of type 'B' or 'b', and this array must + have enough room for at least 8 bytes. The list object will then be + populated with the first three return values above, and the memoryview object + will be resized inplace to the size of the data and filled in with that data. + The same list and memoryview objects can be reused in subsequent calls to + this method, providing a way of receiving data without using the heap. + For example:: + + buf = bytearray(8) + lst = [0, 0, 0, memoryview(buf)] + # No heap memory is allocated in the following call + can.recv(0, lst) + .. method:: CAN.send(data, id, \*, timeout=0, rtr=False) Send a message on the bus: diff --git a/ports/stm32/can.c b/ports/stm32/can.c index 5b5c4ad3f9..bc4f1092cf 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -29,8 +29,10 @@ #include #include "py/objtuple.h" +#include "py/objarray.h" #include "py/runtime.h" #include "py/gc.h" +#include "py/binary.h" #include "py/stream.h" #include "py/mperrno.h" #include "py/mphal.h" @@ -645,18 +647,20 @@ STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t * } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_send_obj, 1, pyb_can_send); -/// \method recv(fifo, *, timeout=5000) +/// \method recv(fifo, list=None, *, timeout=5000) /// /// Receive data on the bus: /// /// - `fifo` is an integer, which is the FIFO to receive on +/// - `list` if not None is a list with at least 4 elements /// - `timeout` is the timeout in milliseconds to wait for the receive. /// /// Return value: buffer of data bytes. STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_fifo, ARG_timeout }; + enum { ARG_fifo, ARG_list, ARG_timeout }; static const mp_arg_t allowed_args[] = { { MP_QSTR_fifo, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_list, MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, }; @@ -700,23 +704,49 @@ STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t * } } - // return the received data - // TODO use a namedtuple (when namedtuple types can be stored in ROM) - mp_obj_tuple_t *tuple = mp_obj_new_tuple(4, NULL); - if (rx_msg.IDE == CAN_ID_STD) { - tuple->items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.StdId); + // Create the tuple, or get the list, that will hold the return values + // Also populate the fourth element, either a new bytes or reuse existing memoryview + mp_obj_t ret_obj = args[ARG_list].u_obj; + mp_obj_t *items; + if (ret_obj == mp_const_none) { + ret_obj = mp_obj_new_tuple(4, NULL); + items = ((mp_obj_tuple_t*)MP_OBJ_TO_PTR(ret_obj))->items; + items[3] = mp_obj_new_bytes(&rx_msg.Data[0], rx_msg.DLC); } else { - tuple->items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.ExtId); + // User should provide a list of length at least 4 to hold the values + if (!MP_OBJ_IS_TYPE(ret_obj, &mp_type_list)) { + mp_raise_TypeError(NULL); + } + mp_obj_list_t *list = MP_OBJ_TO_PTR(ret_obj); + if (list->len < 4) { + mp_raise_ValueError(NULL); + } + items = list->items; + // Fourth element must be a memoryview which we assume points to a + // byte-like array which is large enough, and then we resize it inplace + if (!MP_OBJ_IS_TYPE(items[3], &mp_type_memoryview)) { + mp_raise_TypeError(NULL); + } + mp_obj_array_t *mv = MP_OBJ_TO_PTR(items[3]); + if (!(mv->typecode == (0x80 | BYTEARRAY_TYPECODE) + || (mv->typecode | 0x20) == (0x80 | 'b'))) { + mp_raise_ValueError(NULL); + } + mv->len = rx_msg.DLC; + memcpy(mv->items, &rx_msg.Data[0], rx_msg.DLC); } - tuple->items[1] = rx_msg.RTR == CAN_RTR_REMOTE ? mp_const_true : mp_const_false; - tuple->items[2] = MP_OBJ_NEW_SMALL_INT(rx_msg.FMI); - vstr_t vstr; - vstr_init_len(&vstr, rx_msg.DLC); - for (mp_uint_t i = 0; i < rx_msg.DLC; i++) { - vstr.buf[i] = rx_msg.Data[i]; // Data is uint32_t but holds only 1 byte + + // Populate the first 3 values of the tuple/list + if (rx_msg.IDE == CAN_ID_STD) { + items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.StdId); + } else { + items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.ExtId); } - tuple->items[3] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); - return tuple; + items[1] = rx_msg.RTR == CAN_RTR_REMOTE ? mp_const_true : mp_const_false; + items[2] = MP_OBJ_NEW_SMALL_INT(rx_msg.FMI); + + // Return the result + return ret_obj; } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_recv_obj, 1, pyb_can_recv); From 22c693aa6fc0f325bc42f4da5904244fefbfc5b1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 19 Mar 2018 15:15:39 +1100 Subject: [PATCH 473/828] tests/pyb/can: Update to test pyb.CAN restart, state, info, inplace recv --- tests/pyb/can.py | 87 +++++++++++++++++++++++++++++++++++++++++++- tests/pyb/can.py.exp | 14 +++++++ 2 files changed, 100 insertions(+), 1 deletion(-) diff --git a/tests/pyb/can.py b/tests/pyb/can.py index 0fd8c8368d..8a08ea9a65 100644 --- a/tests/pyb/can.py +++ b/tests/pyb/can.py @@ -4,6 +4,8 @@ except ImportError: print('SKIP') raise SystemExit +from array import array +import micropython import pyb # test we can correctly create by id or name @@ -19,15 +21,27 @@ CAN.initfilterbanks(14) can = CAN(1) print(can) +# Test state when de-init'd +print(can.state() == can.STOPPED) + can.init(CAN.LOOPBACK) print(can) print(can.any(0)) +# Test state when freshly created +print(can.state() == can.ERROR_ACTIVE) + +# Test that restart can be called +can.restart() + +# Test info returns a sensible value +print(can.info()) + # Catch all filter can.setfilter(0, CAN.MASK16, 0, (0, 0, 0, 0)) can.send('abcd', 123, timeout=5000) -print(can.any(0)) +print(can.any(0), can.info()) print(can.recv(0)) can.send('abcd', -1, timeout=5000) @@ -44,6 +58,77 @@ except ValueError: else: print('failed') +# Test that recv can work without allocating memory on the heap + +buf = bytearray(10) +l = [0, 0, 0, memoryview(buf)] +l2 = None + +micropython.heap_lock() + +can.send('', 42) +l2 = can.recv(0, l) +assert l is l2 +print(l, len(l[3]), buf) + +can.send('1234', 42) +l2 = can.recv(0, l) +assert l is l2 +print(l, len(l[3]), buf) + +can.send('01234567', 42) +l2 = can.recv(0, l) +assert l is l2 +print(l, len(l[3]), buf) + +can.send('abc', 42) +l2 = can.recv(0, l) +assert l is l2 +print(l, len(l[3]), buf) + +micropython.heap_unlock() + +# Test that recv can work with different arrays behind the memoryview +can.send('abc', 1) +print(bytes(can.recv(0, [0, 0, 0, memoryview(array('B', range(8)))])[3])) +can.send('def', 1) +print(bytes(can.recv(0, [0, 0, 0, memoryview(array('b', range(8)))])[3])) + +# Test for non-list passed as second arg to recv +can.send('abc', 1) +try: + can.recv(0, 1) +except TypeError: + print('TypeError') + +# Test for too-short-list passed as second arg to recv +can.send('abc', 1) +try: + can.recv(0, [0, 0, 0]) +except ValueError: + print('ValueError') + +# Test for non-memoryview passed as 4th element to recv +can.send('abc', 1) +try: + can.recv(0, [0, 0, 0, 0]) +except TypeError: + print('TypeError') + +# Test for read-only-memoryview passed as 4th element to recv +can.send('abc', 1) +try: + can.recv(0, [0, 0, 0, memoryview(bytes(8))]) +except ValueError: + print('ValueError') + +# Test for bad-typecode-memoryview passed as 4th element to recv +can.send('abc', 1) +try: + can.recv(0, [0, 0, 0, memoryview(array('i', range(8)))]) +except ValueError: + print('ValueError') + del can # Testing extended IDs diff --git a/tests/pyb/can.py.exp b/tests/pyb/can.py.exp index 352e5f9690..687935e7f4 100644 --- a/tests/pyb/can.py.exp +++ b/tests/pyb/can.py.exp @@ -7,13 +7,27 @@ CAN YA CAN YB ValueError YC CAN(1) +True CAN(1, CAN.LOOPBACK, extframe=False, auto_restart=False) False True +[0, 0, 0, 0, 0, 0, 0, 0] +True [0, 0, 0, 0, 0, 0, 1, 0] (123, False, 0, b'abcd') (2047, False, 0, b'abcd') (0, False, 0, b'abcd') passed +[42, False, 0, ] 0 bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +[42, False, 0, ] 4 bytearray(b'1234\x00\x00\x00\x00\x00\x00') +[42, False, 0, ] 8 bytearray(b'01234567\x00\x00') +[42, False, 0, ] 3 bytearray(b'abc34567\x00\x00') +b'abc' +b'def' +TypeError +ValueError +TypeError +ValueError +ValueError CAN(1, CAN.LOOPBACK, extframe=True, auto_restart=False) passed ('0x8', '0x1c', '0xa', b'ok') From 2ebc538d63fedcddf89d8c9f0e86b2bb00ff164d Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Thu, 15 Mar 2018 20:28:48 +0200 Subject: [PATCH 474/828] stm32/dma: Enable H7 DMA descriptors. --- ports/stm32/dma.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/dma.h b/ports/stm32/dma.h index 15a424a358..f265d60357 100644 --- a/ports/stm32/dma.h +++ b/ports/stm32/dma.h @@ -28,7 +28,7 @@ typedef struct _dma_descr_t dma_descr_t; -#if defined(STM32F4) || defined(STM32F7) +#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) extern const dma_descr_t dma_I2C_1_RX; extern const dma_descr_t dma_SPI_3_RX; From 24a9facd897bd8727dc7fc05bdb7a36d5232316e Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Mon, 19 Mar 2018 15:09:00 +0200 Subject: [PATCH 475/828] stm32/i2c: Add H7 I2C timing configurations. Found the timing for full (400 KHz) and FM+ (1MHz) in the HAL examples, and used CubeMX to calculate the standard value (100KHz). --- ports/stm32/i2c.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index f072a75b8f..e17472cb4c 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -131,9 +131,9 @@ const pyb_i2c_obj_t pyb_i2c_obj[] = { #endif }; -#if defined(STM32F7) || defined(STM32L4) +#if defined(STM32F7) || defined(STM32L4) || defined(STM32H7) -// The STM32F0, F3, F7 and L4 use a TIMINGR register rather than ClockSpeed and +// The STM32F0, F3, F7, H7 and L4 use a TIMINGR register rather than ClockSpeed and // DutyCycle. #if defined(STM32F746xx) @@ -161,6 +161,17 @@ const pyb_i2c_obj_t pyb_i2c_obj[] = { #define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL) #define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FAST) +#elif defined(STM32H7) + +// I2C TIMINGs obtained from the STHAL examples. +#define MICROPY_HW_I2C_BAUDRATE_TIMING { \ + {PYB_I2C_SPEED_STANDARD, 0x40604E73}, \ + {PYB_I2C_SPEED_FULL, 0x00901954}, \ + {PYB_I2C_SPEED_FAST, 0x10810915}, \ + } +#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL) +#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FAST) + #elif defined(STM32L4) // The value 0x90112626 was obtained from the DISCOVERY_I2C1_TIMING constant From 1e0a67f2906a019d29fcc25e9ca1bba0267b9f0e Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Mon, 19 Mar 2018 15:10:57 +0200 Subject: [PATCH 476/828] stm32/boards/NUCLEO_H743ZI: Enable hardware I2C support. --- ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h | 8 ++++---- ports/stm32/boards/NUCLEO_H743ZI/pins.csv | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h index 4fe41e0a1b..9642061371 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h @@ -27,10 +27,10 @@ void NUCLEO_H743ZI_board_early_init(void); #define MICROPY_HW_UART_REPL_BAUD 115200 // I2C busses -//#define MICROPY_HW_I2C1_SCL (pin_B8) -//#define MICROPY_HW_I2C1_SDA (pin_B9) -//#define MICROPY_HW_I2C3_SCL (pin_H7) -//#define MICROPY_HW_I2C3_SDA (pin_H8) +#define MICROPY_HW_I2C1_SCL (pin_B8) +#define MICROPY_HW_I2C1_SDA (pin_B9) +#define MICROPY_HW_I2C2_SCL (pin_F1) +#define MICROPY_HW_I2C2_SDA (pin_F0) // SPI //#define MICROPY_HW_SPI2_NSS (pin_I0) diff --git a/ports/stm32/boards/NUCLEO_H743ZI/pins.csv b/ports/stm32/boards/NUCLEO_H743ZI/pins.csv index b0d225368c..82f80764f7 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/pins.csv +++ b/ports/stm32/boards/NUCLEO_H743ZI/pins.csv @@ -30,8 +30,10 @@ TP3,PH15 AUDIO_INT,PD6 AUDIO_SDA,PH8 AUDIO_SCL,PH7 -EXT_SDA,PB9 -EXT_SCL,PB8 +I2C1_SDA,PB9 +I2C1_SCL,PB8 +I2C2_SDA,PF0 +I2C2_SCL,PF1 EXT_RST,PG3 SD_D0,PG9 SD_D1,PG10 From 7b0a020a02595d4ca1e782c8282d01bc220c84c7 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Mon, 19 Mar 2018 15:22:01 +0200 Subject: [PATCH 477/828] stm32/boards/NUCLEO_H743ZI: Disable uSD transceiver. There's no uSD Transceiver on this NUCLEO board. --- ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h index 89421d30b7..19f9563ab0 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h @@ -168,7 +168,7 @@ #define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ #define TICK_INT_PRIORITY ((uint32_t)0x0F) /*!< tick interrupt priority */ #define USE_RTOS 0 -#define USE_SD_TRANSCEIVER 1U /*!< use uSD Transceiver */ +#define USE_SD_TRANSCEIVER 0U /*!< use uSD Transceiver */ /* ########################### Ethernet Configuration ######################### */ #define ETH_TX_DESC_CNT 4 /* number of Ethernet Tx DMA descriptors */ From 23f07b77e55664602354d49fdc6a16032768f293 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 25 Mar 2018 23:58:56 +1100 Subject: [PATCH 478/828] lib/stm32lib: Update library for fix to H7 SPI strict aliasing error. --- lib/stm32lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/stm32lib b/lib/stm32lib index 000df50c23..90b9961963 160000 --- a/lib/stm32lib +++ b/lib/stm32lib @@ -1 +1 @@ -Subproject commit 000df50c233083c7bea05d1fed6fa191a65694bb +Subproject commit 90b9961963b625db0f2aabfe8e5e508b1f4fb7f1 From b63cc1e9efb3618141b8f2cdd19ffd6823b73bb7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 26 Mar 2018 00:00:47 +1100 Subject: [PATCH 479/828] stm32/Makefile: Re-enable strict aliasing optimisation for ST HAL files. The HAL requires strict aliasing optimisation to be turned on to function correctly (at least for the SD card driver on F4 MCUs). This optimisation was recently disabled with the addition of H7 support due to the H7 HAL having errors with the strict aliasing optimisation enabled. But this is now fixed in the latest stm32lib and so the optimisation can now be re-enabled. Thanks to @chuckbook for finding that there was a problem with the SD card on F4 MCUs with the strict aliasing optimisation disabled. --- ports/stm32/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index ba4c90dabe..3f381bde0f 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -253,7 +253,6 @@ SRC_O = \ $(STARTUP_FILE) \ gchelper.o \ -$(BUILD)/$(HAL_DIR)/Src/%.o: CFLAGS += -fno-strict-aliasing SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ hal.c \ hal_adc.c \ From 6b51eb22c8200124bd1639f542f7757edb82e736 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 27 Mar 2018 20:25:24 +1100 Subject: [PATCH 480/828] stm32: Consolidate include of genhdr/pins.h to single location in pin.h. genhdr/pins.h is an internal header file that defines all of the pin objects and it's cleaner to have pin.h include it (where the struct's for these objects are defined) rather than an explicit include by every user. --- ports/stm32/accel.c | 1 - ports/stm32/adc.c | 1 - ports/stm32/boards/STM32L476DISC/bdev.c | 1 - ports/stm32/boards/STM32L476DISC/board_init.c | 1 - ports/stm32/dac.c | 1 - ports/stm32/i2c.c | 1 - ports/stm32/lcd.c | 1 - ports/stm32/led.c | 1 - ports/stm32/machine_i2c.c | 1 - ports/stm32/modnwcc3k.c | 1 - ports/stm32/modnwwiznet5k.c | 1 - ports/stm32/pin.h | 3 +++ ports/stm32/qspi.c | 1 - ports/stm32/sdcard.c | 1 - ports/stm32/servo.c | 1 - ports/stm32/spi.c | 1 - ports/stm32/uart.c | 1 - ports/stm32/usrsw.c | 1 - 18 files changed, 3 insertions(+), 17 deletions(-) diff --git a/ports/stm32/accel.c b/ports/stm32/accel.c index 7b36e20823..8d61fb88d0 100644 --- a/ports/stm32/accel.c +++ b/ports/stm32/accel.c @@ -30,7 +30,6 @@ #include "py/mphal.h" #include "py/runtime.h" #include "pin.h" -#include "genhdr/pins.h" #include "i2c.h" #include "accel.h" diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 781c9aed37..3f38fa2ca2 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -32,7 +32,6 @@ #include "py/mphal.h" #include "adc.h" #include "pin.h" -#include "genhdr/pins.h" #include "timer.h" #if MICROPY_HW_ENABLE_ADC diff --git a/ports/stm32/boards/STM32L476DISC/bdev.c b/ports/stm32/boards/STM32L476DISC/bdev.c index 50a02498ac..0f7791033f 100644 --- a/ports/stm32/boards/STM32L476DISC/bdev.c +++ b/ports/stm32/boards/STM32L476DISC/bdev.c @@ -1,5 +1,4 @@ #include "storage.h" -#include "genhdr/pins.h" // External SPI flash uses standard SPI interface diff --git a/ports/stm32/boards/STM32L476DISC/board_init.c b/ports/stm32/boards/STM32L476DISC/board_init.c index fdc41c4019..30a6c309e0 100644 --- a/ports/stm32/boards/STM32L476DISC/board_init.c +++ b/ports/stm32/boards/STM32L476DISC/board_init.c @@ -1,5 +1,4 @@ #include "py/mphal.h" -#include "genhdr/pins.h" void STM32L476DISC_board_early_init(void) { // set SPI flash WP and HOLD pins high diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c index 9db61964ce..09a86f94c8 100644 --- a/ports/stm32/dac.c +++ b/ports/stm32/dac.c @@ -33,7 +33,6 @@ #include "dac.h" #include "dma.h" #include "pin.h" -#include "genhdr/pins.h" /// \moduleref pyb /// \class DAC - digital to analog conversion diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index e17472cb4c..65a88551e3 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -31,7 +31,6 @@ #include "py/mphal.h" #include "irq.h" #include "pin.h" -#include "genhdr/pins.h" #include "bufhelper.h" #include "dma.h" #include "i2c.h" diff --git a/ports/stm32/lcd.c b/ports/stm32/lcd.c index 62a95c0700..c88ffd4f94 100644 --- a/ports/stm32/lcd.c +++ b/ports/stm32/lcd.c @@ -33,7 +33,6 @@ #if MICROPY_HW_HAS_LCD #include "pin.h" -#include "genhdr/pins.h" #include "bufhelper.h" #include "spi.h" #include "font_petme128_8x8.h" diff --git a/ports/stm32/led.c b/ports/stm32/led.c index 9bbcaa6b30..a95d6c1a4b 100644 --- a/ports/stm32/led.c +++ b/ports/stm32/led.c @@ -31,7 +31,6 @@ #include "timer.h" #include "led.h" #include "pin.h" -#include "genhdr/pins.h" #if defined(MICROPY_HW_LED1) diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c index 2844469ddf..33da4e57e0 100644 --- a/ports/stm32/machine_i2c.c +++ b/ports/stm32/machine_i2c.c @@ -31,7 +31,6 @@ #include "py/mphal.h" #include "py/mperrno.h" #include "extmod/machine_i2c.h" -#include "genhdr/pins.h" #include "i2c.h" #if MICROPY_HW_ENABLE_HW_I2C diff --git a/ports/stm32/modnwcc3k.c b/ports/stm32/modnwcc3k.c index 52787187b0..8723994f45 100644 --- a/ports/stm32/modnwcc3k.c +++ b/ports/stm32/modnwcc3k.c @@ -39,7 +39,6 @@ #include "lib/netutils/netutils.h" #include "modnetwork.h" #include "pin.h" -#include "genhdr/pins.h" #include "spi.h" #include "hci.h" diff --git a/ports/stm32/modnwwiznet5k.c b/ports/stm32/modnwwiznet5k.c index 2fd85531f9..017bd42f88 100644 --- a/ports/stm32/modnwwiznet5k.c +++ b/ports/stm32/modnwwiznet5k.c @@ -36,7 +36,6 @@ #include "lib/netutils/netutils.h" #include "modnetwork.h" #include "pin.h" -#include "genhdr/pins.h" #include "spi.h" #include "ethernet/wizchip_conf.h" diff --git a/ports/stm32/pin.h b/ports/stm32/pin.h index 2439ebbbef..b0e05256fe 100644 --- a/ports/stm32/pin.h +++ b/ports/stm32/pin.h @@ -63,6 +63,9 @@ typedef struct { extern const mp_obj_type_t pin_type; extern const mp_obj_type_t pin_af_type; +// Include all of the individual pin objects +#include "genhdr/pins.h" + typedef struct { const char *name; const pin_obj_t *pin; diff --git a/ports/stm32/qspi.c b/ports/stm32/qspi.c index 50cf5eb487..a6bcb0a0f6 100644 --- a/ports/stm32/qspi.c +++ b/ports/stm32/qspi.c @@ -28,7 +28,6 @@ #include "py/mperrno.h" #include "py/mphal.h" -#include "genhdr/pins.h" #include "qspi.h" #if defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2) diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index 5f13c923e8..9d5ef0e1c3 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -33,7 +33,6 @@ #include "sdcard.h" #include "pin.h" -#include "genhdr/pins.h" #include "bufhelper.h" #include "dma.h" #include "irq.h" diff --git a/ports/stm32/servo.c b/ports/stm32/servo.c index 0e54b4d0af..5e1c2762f7 100644 --- a/ports/stm32/servo.c +++ b/ports/stm32/servo.c @@ -29,7 +29,6 @@ #include "py/runtime.h" #include "py/mphal.h" #include "pin.h" -#include "genhdr/pins.h" #include "timer.h" #include "servo.h" diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c index 6a6a412f74..a8abebee49 100644 --- a/ports/stm32/spi.c +++ b/ports/stm32/spi.c @@ -32,7 +32,6 @@ #include "extmod/machine_spi.h" #include "irq.h" #include "pin.h" -#include "genhdr/pins.h" #include "bufhelper.h" #include "spi.h" diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index 2fcbbd74c6..bc52c9cc9c 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -34,7 +34,6 @@ #include "py/mphal.h" #include "uart.h" #include "irq.h" -#include "genhdr/pins.h" /// \moduleref pyb /// \class UART - duplex serial communication bus diff --git a/ports/stm32/usrsw.c b/ports/stm32/usrsw.c index a7721ad779..8b62210cb7 100644 --- a/ports/stm32/usrsw.c +++ b/ports/stm32/usrsw.c @@ -30,7 +30,6 @@ #include "py/mphal.h" #include "extint.h" #include "pin.h" -#include "genhdr/pins.h" #include "usrsw.h" #if MICROPY_HW_HAS_SWITCH From 6f1e85762409e815dfdd2d563173bf0e8634a6e6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 27 Mar 2018 20:34:55 +1100 Subject: [PATCH 481/828] stm32/qspi: Don't take the address of pin configuration identifiers. Taking the address assumes that the pin is an object (eg a struct), but it could be a literal (eg an int). Not taking the address makes this driver more general for other uses. --- ports/stm32/qspi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ports/stm32/qspi.c b/ports/stm32/qspi.c index a6bcb0a0f6..97f055c099 100644 --- a/ports/stm32/qspi.c +++ b/ports/stm32/qspi.c @@ -34,12 +34,12 @@ void qspi_init(void) { // Configure pins - mp_hal_pin_config(&MICROPY_HW_QSPIFLASH_CS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 10); - mp_hal_pin_config(&MICROPY_HW_QSPIFLASH_SCK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); - mp_hal_pin_config(&MICROPY_HW_QSPIFLASH_IO0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); - mp_hal_pin_config(&MICROPY_HW_QSPIFLASH_IO1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); - mp_hal_pin_config(&MICROPY_HW_QSPIFLASH_IO2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); - mp_hal_pin_config(&MICROPY_HW_QSPIFLASH_IO3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); + mp_hal_pin_config(MICROPY_HW_QSPIFLASH_CS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 10); + mp_hal_pin_config(MICROPY_HW_QSPIFLASH_SCK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); + mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); + mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); + mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); + mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); // Bring up the QSPI peripheral From a6009a9e3569b93fd2209f041576931bdc4811f0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 27 Mar 2018 20:38:57 +1100 Subject: [PATCH 482/828] stm32/*bdev.c: Eliminate dependency on sys_tick_has_passed. Explicitly writing out the implementation of sys_tick_has_passed makes these bdev files independent of systick.c and more reusable as a general component. It also reduces the code size slightly. The irq.h header is added to spibdev.c because it uses declarations in that file (irq.h is usually included implicitly via mphalport.h but not always). --- ports/stm32/flashbdev.c | 3 +-- ports/stm32/spibdev.c | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c index 64faf0eacd..4245dd1ec5 100644 --- a/ports/stm32/flashbdev.c +++ b/ports/stm32/flashbdev.c @@ -29,7 +29,6 @@ #include "py/obj.h" #include "py/mperrno.h" -#include "systick.h" #include "led.h" #include "flash.h" #include "storage.h" @@ -231,7 +230,7 @@ static void flash_bdev_irq_handler(void) { // If not a forced write, wait at least 5 seconds after last write to flush // On file close and flash unmount we get a forced write, so we can afford to wait a while - if ((flash_flags & FLASH_FLAG_FORCE_WRITE) || sys_tick_has_passed(flash_tick_counter_last_write, 5000)) { + if ((flash_flags & FLASH_FLAG_FORCE_WRITE) || HAL_GetTick() - flash_tick_counter_last_write >= 5000) { // sync the cache RAM buffer by writing it to the flash page flash_write(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4); // clear the flash flags now that we have a clean cache diff --git a/ports/stm32/spibdev.c b/ports/stm32/spibdev.c index 007a96a6ca..91ec4df5e9 100644 --- a/ports/stm32/spibdev.c +++ b/ports/stm32/spibdev.c @@ -26,7 +26,7 @@ #include "py/obj.h" #include "py/mperrno.h" -#include "systick.h" +#include "irq.h" #include "led.h" #include "storage.h" @@ -39,7 +39,7 @@ int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) { return 0; case BDEV_IOCTL_IRQ_HANDLER: - if ((bdev->spiflash.flags & 1) && sys_tick_has_passed(bdev->flash_tick_counter_last_write, 1000)) { + if ((bdev->spiflash.flags & 1) && HAL_GetTick() - bdev->flash_tick_counter_last_write >= 1000) { mp_spiflash_flush(&bdev->spiflash); led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off } From 7aec06ca9abb8e07ffce09b5a755e2a6f61b6749 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 27 Mar 2018 21:17:48 +1100 Subject: [PATCH 483/828] stm32/boards: Allow boards to have finer control over the linker script. This patch allows a particular board to independently specify the linker scripts for 1) the MCU memory layout; 2) how the different firmware sections are arranged in memory. Right now all boards follow the same layout with two separate firmware section, one for the ISR and one for the text and data. This leaves room for storage (filesystem data) to live between the firmware sections. The idea with this patch is to accommodate boards that don't have internal flash storage and only need to have one continuous firmware section. Thus the common.ld script is renamed to common_ifs.ld to make explicit that it is used for cases where the board has internal flash storage. --- ports/stm32/Makefile | 2 +- ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk | 2 +- ports/stm32/boards/CERB40/mpconfigboard.mk | 2 +- ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk | 2 +- ports/stm32/boards/HYDRABUS/mpconfigboard.mk | 2 +- ports/stm32/boards/LIMIFROG/mpconfigboard.mk | 2 +- ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk | 2 +- ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk | 2 +- ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk | 2 +- ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk | 2 +- ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk | 2 +- ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk | 2 +- ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk | 2 +- ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk | 2 +- ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk | 2 +- ports/stm32/boards/PYBLITEV10/mpconfigboard.mk | 2 +- ports/stm32/boards/PYBV10/mpconfigboard.mk | 2 +- ports/stm32/boards/PYBV11/mpconfigboard.mk | 2 +- ports/stm32/boards/PYBV3/mpconfigboard.mk | 2 +- ports/stm32/boards/PYBV4/mpconfigboard.mk | 2 +- ports/stm32/boards/STM32F411DISC/mpconfigboard.mk | 2 +- ports/stm32/boards/STM32F429DISC/mpconfigboard.mk | 2 +- ports/stm32/boards/STM32F439/mpconfigboard.mk | 2 +- ports/stm32/boards/STM32F4DISC/mpconfigboard.mk | 2 +- ports/stm32/boards/STM32F769DISC/mpconfigboard.mk | 2 +- ports/stm32/boards/STM32F7DISC/mpconfigboard.mk | 2 +- ports/stm32/boards/STM32L476DISC/mpconfigboard.mk | 2 +- ports/stm32/boards/{common.ld => common_ifs.ld} | 13 +++++++++++++ ports/stm32/boards/stm32f401xd.ld | 3 --- ports/stm32/boards/stm32f401xe.ld | 3 --- ports/stm32/boards/stm32f405.ld | 3 --- ports/stm32/boards/stm32f411.ld | 3 --- ports/stm32/boards/stm32f429.ld | 3 --- ports/stm32/boards/stm32f439.ld | 3 --- ports/stm32/boards/stm32f746.ld | 3 --- ports/stm32/boards/stm32f767.ld | 3 --- ports/stm32/boards/stm32f769.ld | 3 --- ports/stm32/boards/stm32l476xe.ld | 3 --- ports/stm32/boards/stm32l476xg.ld | 3 --- 39 files changed, 40 insertions(+), 60 deletions(-) rename ports/stm32/boards/{common.ld => common_ifs.ld} (92%) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 3f381bde0f..7393ebcd2c 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -80,7 +80,7 @@ CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_FLOAT CFLAGS += -fsingle-precision-constant -Wdouble-promotion endif -LDFLAGS = -nostdlib -L $(LD_DIR) -T $(LD_FILE) -Map=$(@:.elf=.map) --cref +LDFLAGS = -nostdlib -L $(LD_DIR) $(addprefix -T,$(LD_FILES)) -Map=$(@:.elf=.map) --cref LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) # Remove uncalled code from the final image. diff --git a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk index 1ba61a3274..3c94fc61da 100644 --- a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk +++ b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk @@ -3,6 +3,6 @@ CMSIS_MCU = STM32L475xx # The stm32l475 does not have a LDC controller which is # the only diffrence to the stm32l476 - so reuse some files. AF_FILE = boards/stm32l476_af.csv -LD_FILE = boards/stm32l476xg.ld +LD_FILES = boards/stm32l476xg.ld boards/common_ifs.ld TEXT_ADDR = 0x08004000 OPENOCD_CONFIG = boards/openocd_stm32l4.cfg diff --git a/ports/stm32/boards/CERB40/mpconfigboard.mk b/ports/stm32/boards/CERB40/mpconfigboard.mk index 5734c66904..27198edb03 100644 --- a/ports/stm32/boards/CERB40/mpconfigboard.mk +++ b/ports/stm32/boards/CERB40/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv -LD_FILE = boards/stm32f405.ld +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk index d531a594a1..e95672d3a6 100644 --- a/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk +++ b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk @@ -1,7 +1,7 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F401xE AF_FILE = boards/stm32f401_af.csv -LD_FILE = boards/stm32f401xd.ld +LD_FILES = boards/stm32f401xd.ld boards/common_ifs.ld # Don't include default frozen modules because MCU is tight on flash space FROZEN_MPY_DIR ?= diff --git a/ports/stm32/boards/HYDRABUS/mpconfigboard.mk b/ports/stm32/boards/HYDRABUS/mpconfigboard.mk index 5734c66904..27198edb03 100644 --- a/ports/stm32/boards/HYDRABUS/mpconfigboard.mk +++ b/ports/stm32/boards/HYDRABUS/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv -LD_FILE = boards/stm32f405.ld +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/LIMIFROG/mpconfigboard.mk b/ports/stm32/boards/LIMIFROG/mpconfigboard.mk index a1304b6559..50a831047c 100644 --- a/ports/stm32/boards/LIMIFROG/mpconfigboard.mk +++ b/ports/stm32/boards/LIMIFROG/mpconfigboard.mk @@ -1,5 +1,5 @@ MCU_SERIES = l4 CMSIS_MCU = STM32L476xx AF_FILE = boards/stm32l476_af.csv -LD_FILE = boards/stm32l476xe.ld +LD_FILES = boards/stm32l476xe.ld boards/common_ifs.ld TEXT_ADDR = 0x08004000 diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk index 5734c66904..27198edb03 100644 --- a/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk +++ b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv -LD_FILE = boards/stm32f405.ld +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk index eb391bed73..00b915b84b 100644 --- a/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F401xE AF_FILE = boards/stm32f401_af.csv -LD_FILE = boards/stm32f401xe.ld +LD_FILES = boards/stm32f401xe.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk index 71b3b19d65..4e57879c76 100644 --- a/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F411xE AF_FILE = boards/stm32f411_af.csv -LD_FILE = boards/stm32f411.ld +LD_FILES = boards/stm32f411.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk index 1bbf808b69..9d200ce702 100644 --- a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F429xx AF_FILE = boards/stm32f429_af.csv -LD_FILE = boards/stm32f429.ld +LD_FILES = boards/stm32f429.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk index e1ec6d57cf..43057458f1 100644 --- a/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F446xx AF_FILE = boards/stm32f429_af.csv -LD_FILE = boards/stm32f411.ld +LD_FILES = boards/stm32f411.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk index 7c6bc4584a..cf03fbc670 100644 --- a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = f7 CMSIS_MCU = STM32F746xx AF_FILE = boards/stm32f746_af.csv -LD_FILE = boards/stm32f746.ld +LD_FILES = boards/stm32f746.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk index ba28a16e1e..afb2ac8056 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk @@ -2,4 +2,4 @@ MCU_SERIES = f7 CMSIS_MCU = STM32F767xx MICROPY_FLOAT_IMPL = double AF_FILE = boards/stm32f767_af.csv -LD_FILE = boards/stm32f767.ld +LD_FILES = boards/stm32f767.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk index abb4a35707..336f543ac7 100644 --- a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk @@ -1,5 +1,5 @@ MCU_SERIES = l4 CMSIS_MCU = STM32L476xx AF_FILE = boards/stm32l476_af.csv -LD_FILE = boards/stm32l476xg.ld +LD_FILES = boards/stm32l476xg.ld boards/common_ifs.ld TEXT_ADDR = 0x08004000 diff --git a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk index ece09caa13..e874cf5cc1 100644 --- a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk +++ b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F407xx AF_FILE = boards/stm32f405_af.csv -LD_FILE = boards/stm32f405.ld +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk b/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk index 71b3b19d65..4e57879c76 100644 --- a/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk +++ b/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F411xE AF_FILE = boards/stm32f411_af.csv -LD_FILE = boards/stm32f411.ld +LD_FILES = boards/stm32f411.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/PYBV10/mpconfigboard.mk b/ports/stm32/boards/PYBV10/mpconfigboard.mk index 5734c66904..27198edb03 100644 --- a/ports/stm32/boards/PYBV10/mpconfigboard.mk +++ b/ports/stm32/boards/PYBV10/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv -LD_FILE = boards/stm32f405.ld +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/PYBV11/mpconfigboard.mk b/ports/stm32/boards/PYBV11/mpconfigboard.mk index 5734c66904..27198edb03 100644 --- a/ports/stm32/boards/PYBV11/mpconfigboard.mk +++ b/ports/stm32/boards/PYBV11/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv -LD_FILE = boards/stm32f405.ld +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/PYBV3/mpconfigboard.mk b/ports/stm32/boards/PYBV3/mpconfigboard.mk index 5734c66904..27198edb03 100644 --- a/ports/stm32/boards/PYBV3/mpconfigboard.mk +++ b/ports/stm32/boards/PYBV3/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv -LD_FILE = boards/stm32f405.ld +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/PYBV4/mpconfigboard.mk b/ports/stm32/boards/PYBV4/mpconfigboard.mk index 5734c66904..27198edb03 100644 --- a/ports/stm32/boards/PYBV4/mpconfigboard.mk +++ b/ports/stm32/boards/PYBV4/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv -LD_FILE = boards/stm32f405.ld +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/STM32F411DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F411DISC/mpconfigboard.mk index 71b3b19d65..4e57879c76 100644 --- a/ports/stm32/boards/STM32F411DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F411DISC/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F411xE AF_FILE = boards/stm32f411_af.csv -LD_FILE = boards/stm32f411.ld +LD_FILES = boards/stm32f411.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk index 1bbf808b69..9d200ce702 100644 --- a/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F429xx AF_FILE = boards/stm32f429_af.csv -LD_FILE = boards/stm32f429.ld +LD_FILES = boards/stm32f429.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/STM32F439/mpconfigboard.mk b/ports/stm32/boards/STM32F439/mpconfigboard.mk index 0c30c06a30..051bd21e68 100644 --- a/ports/stm32/boards/STM32F439/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F439/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F439xx AF_FILE = boards/stm32f439_af.csv -LD_FILE = boards/stm32f439.ld +LD_FILES = boards/stm32f439.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk index ece09caa13..e874cf5cc1 100644 --- a/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F407xx AF_FILE = boards/stm32f405_af.csv -LD_FILE = boards/stm32f405.ld +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk index 99234e4cf1..7271fdd9b0 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk @@ -2,4 +2,4 @@ MCU_SERIES = f7 CMSIS_MCU = STM32F769xx MICROPY_FLOAT_IMPL = double AF_FILE = boards/stm32f767_af.csv -LD_FILE = boards/stm32f769.ld +LD_FILES = boards/stm32f769.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk index 7c6bc4584a..cf03fbc670 100644 --- a/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk @@ -1,4 +1,4 @@ MCU_SERIES = f7 CMSIS_MCU = STM32F746xx AF_FILE = boards/stm32f746_af.csv -LD_FILE = boards/stm32f746.ld +LD_FILES = boards/stm32f746.ld boards/common_ifs.ld diff --git a/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk b/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk index 72468d89ce..4128f4886d 100644 --- a/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk @@ -1,6 +1,6 @@ MCU_SERIES = l4 CMSIS_MCU = STM32L476xx AF_FILE = boards/stm32l476_af.csv -LD_FILE = boards/stm32l476xg.ld +LD_FILES = boards/stm32l476xg.ld boards/common_ifs.ld TEXT_ADDR = 0x08004000 OPENOCD_CONFIG = boards/openocd_stm32l4.cfg diff --git a/ports/stm32/boards/common.ld b/ports/stm32/boards/common_ifs.ld similarity index 92% rename from ports/stm32/boards/common.ld rename to ports/stm32/boards/common_ifs.ld index e5dea49d08..74b2ffb419 100644 --- a/ports/stm32/boards/common.ld +++ b/ports/stm32/boards/common_ifs.ld @@ -1,3 +1,16 @@ +/* Memory layout for internal flash storage configuration: + + FLASH_ISR .isr_vector + + FLASH_TEXT .text + FLASH_TEXT .data + + RAM .data + RAM .bss + RAM .heap + RAM .stack +*/ + ENTRY(Reset_Handler) /* define output sections */ diff --git a/ports/stm32/boards/stm32f401xd.ld b/ports/stm32/boards/stm32f401xd.ld index 89f6056096..7c0e790185 100644 --- a/ports/stm32/boards/stm32f401xd.ld +++ b/ports/stm32/boards/stm32f401xd.ld @@ -21,9 +21,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f401xe.ld b/ports/stm32/boards/stm32f401xe.ld index ae2f899048..e76bbad1c2 100644 --- a/ports/stm32/boards/stm32f401xe.ld +++ b/ports/stm32/boards/stm32f401xe.ld @@ -21,9 +21,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f405.ld b/ports/stm32/boards/stm32f405.ld index c6107913f2..0375491f65 100644 --- a/ports/stm32/boards/stm32f405.ld +++ b/ports/stm32/boards/stm32f405.ld @@ -22,9 +22,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f411.ld b/ports/stm32/boards/stm32f411.ld index 7adfa35c95..9e3e6bc154 100644 --- a/ports/stm32/boards/stm32f411.ld +++ b/ports/stm32/boards/stm32f411.ld @@ -21,9 +21,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f429.ld b/ports/stm32/boards/stm32f429.ld index a0931684d2..d80f7f5416 100644 --- a/ports/stm32/boards/stm32f429.ld +++ b/ports/stm32/boards/stm32f429.ld @@ -22,9 +22,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f439.ld b/ports/stm32/boards/stm32f439.ld index a76a0ebc79..16c606eccc 100644 --- a/ports/stm32/boards/stm32f439.ld +++ b/ports/stm32/boards/stm32f439.ld @@ -21,9 +21,6 @@ _minimum_heap_size = 16K; /* top end of the stack */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f746.ld b/ports/stm32/boards/stm32f746.ld index ce5e85bb6d..b5864453dd 100644 --- a/ports/stm32/boards/stm32f746.ld +++ b/ports/stm32/boards/stm32f746.ld @@ -22,9 +22,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f767.ld b/ports/stm32/boards/stm32f767.ld index 225abd810f..7e34a90d52 100644 --- a/ports/stm32/boards/stm32f767.ld +++ b/ports/stm32/boards/stm32f767.ld @@ -22,9 +22,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f769.ld b/ports/stm32/boards/stm32f769.ld index c4cabe7a4d..d6da439435 100644 --- a/ports/stm32/boards/stm32f769.ld +++ b/ports/stm32/boards/stm32f769.ld @@ -22,9 +22,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32l476xe.ld b/ports/stm32/boards/stm32l476xe.ld index 11b2972ade..76f94444eb 100644 --- a/ports/stm32/boards/stm32l476xe.ld +++ b/ports/stm32/boards/stm32l476xe.ld @@ -22,9 +22,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32l476xg.ld b/ports/stm32/boards/stm32l476xg.ld index a94fa27504..83bb23901e 100644 --- a/ports/stm32/boards/stm32l476xg.ld +++ b/ports/stm32/boards/stm32l476xg.ld @@ -24,9 +24,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); From 95b2cb008e22a26b398b3c153243269b2ffc3b6f Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 27 Mar 2018 21:20:04 +1100 Subject: [PATCH 484/828] stm32/Makefile: Rename FLASH_ADDR/TEXT_ADDR to TEXT0_ADDR/TEXT1_ADDR. To make it clearer that these addresses are both for firmware text and that they have a prescribed ordering. --- ports/stm32/Makefile | 12 ++++++------ ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk | 2 +- ports/stm32/boards/LIMIFROG/mpconfigboard.mk | 2 +- ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk | 2 +- ports/stm32/boards/STM32L476DISC/mpconfigboard.mk | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 7393ebcd2c..858e8fa954 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -387,24 +387,24 @@ else $(Q)$(DFU_UTIL) -a 0 -d $(DEVICE) -D $< endif -FLASH_ADDR ?= 0x08000000 -TEXT_ADDR ?= 0x08020000 +TEXT0_ADDR ?= 0x08000000 +TEXT1_ADDR ?= 0x08020000 deploy-stlink: $(BUILD)/firmware.dfu $(ECHO) "Writing $(BUILD)/firmware0.bin to the board via ST-LINK" - $(Q)$(STFLASH) write $(BUILD)/firmware0.bin $(FLASH_ADDR) + $(Q)$(STFLASH) write $(BUILD)/firmware0.bin $(TEXT0_ADDR) $(ECHO) "Writing $(BUILD)/firmware1.bin to the board via ST-LINK" - $(Q)$(STFLASH) --reset write $(BUILD)/firmware1.bin $(TEXT_ADDR) + $(Q)$(STFLASH) --reset write $(BUILD)/firmware1.bin $(TEXT1_ADDR) deploy-openocd: $(BUILD)/firmware.dfu $(ECHO) "Writing $(BUILD)/firmware{0,1}.bin to the board via ST-LINK using OpenOCD" - $(Q)$(OPENOCD) -f $(OPENOCD_CONFIG) -c "stm_flash $(BUILD)/firmware0.bin $(FLASH_ADDR) $(BUILD)/firmware1.bin $(TEXT_ADDR)" + $(Q)$(OPENOCD) -f $(OPENOCD_CONFIG) -c "stm_flash $(BUILD)/firmware0.bin $(TEXT0_ADDR) $(BUILD)/firmware1.bin $(TEXT1_ADDR)" $(BUILD)/firmware.dfu: $(BUILD)/firmware.elf $(ECHO) "GEN $@" $(Q)$(OBJCOPY) -O binary -j .isr_vector $^ $(BUILD)/firmware0.bin $(Q)$(OBJCOPY) -O binary -j .text -j .data $^ $(BUILD)/firmware1.bin - $(Q)$(PYTHON) $(DFU) -b $(FLASH_ADDR):$(BUILD)/firmware0.bin -b $(TEXT_ADDR):$(BUILD)/firmware1.bin $@ + $(Q)$(PYTHON) $(DFU) -b $(TEXT0_ADDR):$(BUILD)/firmware0.bin -b $(TEXT1_ADDR):$(BUILD)/firmware1.bin $@ $(BUILD)/firmware.hex: $(BUILD)/firmware.elf $(ECHO) "GEN $@" diff --git a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk index 3c94fc61da..7e7bfcce9a 100644 --- a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk +++ b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk @@ -4,5 +4,5 @@ CMSIS_MCU = STM32L475xx # the only diffrence to the stm32l476 - so reuse some files. AF_FILE = boards/stm32l476_af.csv LD_FILES = boards/stm32l476xg.ld boards/common_ifs.ld -TEXT_ADDR = 0x08004000 +TEXT1_ADDR = 0x08004000 OPENOCD_CONFIG = boards/openocd_stm32l4.cfg diff --git a/ports/stm32/boards/LIMIFROG/mpconfigboard.mk b/ports/stm32/boards/LIMIFROG/mpconfigboard.mk index 50a831047c..02e8a06b28 100644 --- a/ports/stm32/boards/LIMIFROG/mpconfigboard.mk +++ b/ports/stm32/boards/LIMIFROG/mpconfigboard.mk @@ -2,4 +2,4 @@ MCU_SERIES = l4 CMSIS_MCU = STM32L476xx AF_FILE = boards/stm32l476_af.csv LD_FILES = boards/stm32l476xe.ld boards/common_ifs.ld -TEXT_ADDR = 0x08004000 +TEXT1_ADDR = 0x08004000 diff --git a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk index 336f543ac7..3244fb628a 100644 --- a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk @@ -2,4 +2,4 @@ MCU_SERIES = l4 CMSIS_MCU = STM32L476xx AF_FILE = boards/stm32l476_af.csv LD_FILES = boards/stm32l476xg.ld boards/common_ifs.ld -TEXT_ADDR = 0x08004000 +TEXT1_ADDR = 0x08004000 diff --git a/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk b/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk index 4128f4886d..27935dad8f 100644 --- a/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk @@ -2,5 +2,5 @@ MCU_SERIES = l4 CMSIS_MCU = STM32L476xx AF_FILE = boards/stm32l476_af.csv LD_FILES = boards/stm32l476xg.ld boards/common_ifs.ld -TEXT_ADDR = 0x08004000 +TEXT1_ADDR = 0x08004000 OPENOCD_CONFIG = boards/openocd_stm32l4.cfg From ed75b2655fd8e5f9c058a97852eb30f354c10206 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 27 Mar 2018 21:24:15 +1100 Subject: [PATCH 485/828] stm32/Makefile: Allow a board to config either 1 or 2 firmware sections. This patch forces a board to explicitly define TEXT1_ADDR in order to split the firmware into two separate pieces. Otherwise the default is now to produce only a single continuous firmware image with all ISR, text and data together. --- ports/stm32/Makefile | 25 ++++++++++++++++++- .../boards/B_L475E_IOT01A/mpconfigboard.mk | 1 + ports/stm32/boards/CERB40/mpconfigboard.mk | 2 ++ .../boards/ESPRUINO_PICO/mpconfigboard.mk | 2 ++ ports/stm32/boards/HYDRABUS/mpconfigboard.mk | 2 ++ ports/stm32/boards/LIMIFROG/mpconfigboard.mk | 1 + .../boards/NETDUINO_PLUS_2/mpconfigboard.mk | 2 ++ .../boards/NUCLEO_F401RE/mpconfigboard.mk | 2 ++ .../boards/NUCLEO_F411RE/mpconfigboard.mk | 2 ++ .../boards/NUCLEO_F429ZI/mpconfigboard.mk | 2 ++ .../boards/NUCLEO_F446RE/mpconfigboard.mk | 2 ++ .../boards/NUCLEO_F746ZG/mpconfigboard.mk | 2 ++ .../boards/NUCLEO_F767ZI/mpconfigboard.mk | 2 ++ .../boards/NUCLEO_L476RG/mpconfigboard.mk | 1 + .../stm32/boards/OLIMEX_E407/mpconfigboard.mk | 2 ++ .../stm32/boards/PYBLITEV10/mpconfigboard.mk | 2 ++ ports/stm32/boards/PYBV10/mpconfigboard.mk | 2 ++ ports/stm32/boards/PYBV11/mpconfigboard.mk | 2 ++ ports/stm32/boards/PYBV3/mpconfigboard.mk | 2 ++ ports/stm32/boards/PYBV4/mpconfigboard.mk | 2 ++ .../boards/STM32F411DISC/mpconfigboard.mk | 2 ++ .../boards/STM32F429DISC/mpconfigboard.mk | 2 ++ ports/stm32/boards/STM32F439/mpconfigboard.mk | 2 ++ .../stm32/boards/STM32F4DISC/mpconfigboard.mk | 2 ++ .../boards/STM32F769DISC/mpconfigboard.mk | 2 ++ .../stm32/boards/STM32F7DISC/mpconfigboard.mk | 2 ++ .../boards/STM32L476DISC/mpconfigboard.mk | 1 + 27 files changed, 72 insertions(+), 1 deletion(-) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 858e8fa954..d1c5de6d33 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -387,8 +387,29 @@ else $(Q)$(DFU_UTIL) -a 0 -d $(DEVICE) -D $< endif +# A board should specify TEXT0_ADDR if to use a different location than the +# default for the firmware memory location. A board can also optionally define +# TEXT1_ADDR to split the firmware into two sections; see below for details. TEXT0_ADDR ?= 0x08000000 -TEXT1_ADDR ?= 0x08020000 + +ifeq ($(TEXT1_ADDR),) +# No TEXT1_ADDR given so put all firmware at TEXT0_ADDR location + +deploy-stlink: $(BUILD)/firmware.dfu + $(ECHO) "Writing $(BUILD)/firmware.bin to the board via ST-LINK" + $(Q)$(STFLASH) write $(BUILD)/firmware.bin $(TEXT0_ADDR) + +deploy-openocd: $(BUILD)/firmware.dfu + $(ECHO) "Writing $(BUILD)/firmware.bin to the board via ST-LINK using OpenOCD" + $(Q)$(OPENOCD) -f $(OPENOCD_CONFIG) -c "stm_flash $(BUILD)/firmware.bin $(TEXT0_ADDR)" + +$(BUILD)/firmware.dfu: $(BUILD)/firmware.elf + $(ECHO) "Create $@" + $(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data $^ $(BUILD)/firmware.bin + $(Q)$(PYTHON) $(DFU) -b $(TEXT0_ADDR):$(BUILD)/firmware.bin $@ + +else +# TEXT0_ADDR and TEXT1_ADDR are specified so split firmware between these locations deploy-stlink: $(BUILD)/firmware.dfu $(ECHO) "Writing $(BUILD)/firmware0.bin to the board via ST-LINK" @@ -406,6 +427,8 @@ $(BUILD)/firmware.dfu: $(BUILD)/firmware.elf $(Q)$(OBJCOPY) -O binary -j .text -j .data $^ $(BUILD)/firmware1.bin $(Q)$(PYTHON) $(DFU) -b $(TEXT0_ADDR):$(BUILD)/firmware0.bin -b $(TEXT1_ADDR):$(BUILD)/firmware1.bin $@ +endif + $(BUILD)/firmware.hex: $(BUILD)/firmware.elf $(ECHO) "GEN $@" $(Q)$(OBJCOPY) -O ihex $< $@ diff --git a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk index 7e7bfcce9a..55e443e919 100644 --- a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk +++ b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk @@ -4,5 +4,6 @@ CMSIS_MCU = STM32L475xx # the only diffrence to the stm32l476 - so reuse some files. AF_FILE = boards/stm32l476_af.csv LD_FILES = boards/stm32l476xg.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 TEXT1_ADDR = 0x08004000 OPENOCD_CONFIG = boards/openocd_stm32l4.cfg diff --git a/ports/stm32/boards/CERB40/mpconfigboard.mk b/ports/stm32/boards/CERB40/mpconfigboard.mk index 27198edb03..40972b3850 100644 --- a/ports/stm32/boards/CERB40/mpconfigboard.mk +++ b/ports/stm32/boards/CERB40/mpconfigboard.mk @@ -2,3 +2,5 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk index e95672d3a6..16cacc089e 100644 --- a/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk +++ b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk @@ -2,6 +2,8 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F401xE AF_FILE = boards/stm32f401_af.csv LD_FILES = boards/stm32f401xd.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 # Don't include default frozen modules because MCU is tight on flash space FROZEN_MPY_DIR ?= diff --git a/ports/stm32/boards/HYDRABUS/mpconfigboard.mk b/ports/stm32/boards/HYDRABUS/mpconfigboard.mk index 27198edb03..40972b3850 100644 --- a/ports/stm32/boards/HYDRABUS/mpconfigboard.mk +++ b/ports/stm32/boards/HYDRABUS/mpconfigboard.mk @@ -2,3 +2,5 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/LIMIFROG/mpconfigboard.mk b/ports/stm32/boards/LIMIFROG/mpconfigboard.mk index 02e8a06b28..2adc98f0b1 100644 --- a/ports/stm32/boards/LIMIFROG/mpconfigboard.mk +++ b/ports/stm32/boards/LIMIFROG/mpconfigboard.mk @@ -2,4 +2,5 @@ MCU_SERIES = l4 CMSIS_MCU = STM32L476xx AF_FILE = boards/stm32l476_af.csv LD_FILES = boards/stm32l476xe.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 TEXT1_ADDR = 0x08004000 diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk index 27198edb03..40972b3850 100644 --- a/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk +++ b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk @@ -2,3 +2,5 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk index 00b915b84b..4c3022f544 100644 --- a/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk @@ -2,3 +2,5 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F401xE AF_FILE = boards/stm32f401_af.csv LD_FILES = boards/stm32f401xe.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk index 4e57879c76..df95065225 100644 --- a/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk @@ -2,3 +2,5 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F411xE AF_FILE = boards/stm32f411_af.csv LD_FILES = boards/stm32f411.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk index 9d200ce702..d19a35c316 100644 --- a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk @@ -2,3 +2,5 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F429xx AF_FILE = boards/stm32f429_af.csv LD_FILES = boards/stm32f429.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk index 43057458f1..64a80e992b 100644 --- a/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk @@ -2,3 +2,5 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F446xx AF_FILE = boards/stm32f429_af.csv LD_FILES = boards/stm32f411.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk index cf03fbc670..160218fd33 100644 --- a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk @@ -2,3 +2,5 @@ MCU_SERIES = f7 CMSIS_MCU = STM32F746xx AF_FILE = boards/stm32f746_af.csv LD_FILES = boards/stm32f746.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk index afb2ac8056..b79ee7da20 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk @@ -3,3 +3,5 @@ CMSIS_MCU = STM32F767xx MICROPY_FLOAT_IMPL = double AF_FILE = boards/stm32f767_af.csv LD_FILES = boards/stm32f767.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk index 3244fb628a..38ae5af212 100644 --- a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk @@ -2,4 +2,5 @@ MCU_SERIES = l4 CMSIS_MCU = STM32L476xx AF_FILE = boards/stm32l476_af.csv LD_FILES = boards/stm32l476xg.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 TEXT1_ADDR = 0x08004000 diff --git a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk index e874cf5cc1..b154dcfbac 100644 --- a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk +++ b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk @@ -2,3 +2,5 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F407xx AF_FILE = boards/stm32f405_af.csv LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk b/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk index 4e57879c76..df95065225 100644 --- a/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk +++ b/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk @@ -2,3 +2,5 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F411xE AF_FILE = boards/stm32f411_af.csv LD_FILES = boards/stm32f411.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/PYBV10/mpconfigboard.mk b/ports/stm32/boards/PYBV10/mpconfigboard.mk index 27198edb03..40972b3850 100644 --- a/ports/stm32/boards/PYBV10/mpconfigboard.mk +++ b/ports/stm32/boards/PYBV10/mpconfigboard.mk @@ -2,3 +2,5 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/PYBV11/mpconfigboard.mk b/ports/stm32/boards/PYBV11/mpconfigboard.mk index 27198edb03..40972b3850 100644 --- a/ports/stm32/boards/PYBV11/mpconfigboard.mk +++ b/ports/stm32/boards/PYBV11/mpconfigboard.mk @@ -2,3 +2,5 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/PYBV3/mpconfigboard.mk b/ports/stm32/boards/PYBV3/mpconfigboard.mk index 27198edb03..40972b3850 100644 --- a/ports/stm32/boards/PYBV3/mpconfigboard.mk +++ b/ports/stm32/boards/PYBV3/mpconfigboard.mk @@ -2,3 +2,5 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/PYBV4/mpconfigboard.mk b/ports/stm32/boards/PYBV4/mpconfigboard.mk index 27198edb03..40972b3850 100644 --- a/ports/stm32/boards/PYBV4/mpconfigboard.mk +++ b/ports/stm32/boards/PYBV4/mpconfigboard.mk @@ -2,3 +2,5 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/STM32F411DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F411DISC/mpconfigboard.mk index 4e57879c76..df95065225 100644 --- a/ports/stm32/boards/STM32F411DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F411DISC/mpconfigboard.mk @@ -2,3 +2,5 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F411xE AF_FILE = boards/stm32f411_af.csv LD_FILES = boards/stm32f411.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk index 9d200ce702..d19a35c316 100644 --- a/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk @@ -2,3 +2,5 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F429xx AF_FILE = boards/stm32f429_af.csv LD_FILES = boards/stm32f429.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/STM32F439/mpconfigboard.mk b/ports/stm32/boards/STM32F439/mpconfigboard.mk index 051bd21e68..ca97acbf61 100644 --- a/ports/stm32/boards/STM32F439/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F439/mpconfigboard.mk @@ -2,3 +2,5 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F439xx AF_FILE = boards/stm32f439_af.csv LD_FILES = boards/stm32f439.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk index e874cf5cc1..b154dcfbac 100644 --- a/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk @@ -2,3 +2,5 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F407xx AF_FILE = boards/stm32f405_af.csv LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk index 7271fdd9b0..873368ce5d 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk @@ -3,3 +3,5 @@ CMSIS_MCU = STM32F769xx MICROPY_FLOAT_IMPL = double AF_FILE = boards/stm32f767_af.csv LD_FILES = boards/stm32f769.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk index cf03fbc670..160218fd33 100644 --- a/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk @@ -2,3 +2,5 @@ MCU_SERIES = f7 CMSIS_MCU = STM32F746xx AF_FILE = boards/stm32f746_af.csv LD_FILES = boards/stm32f746.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk b/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk index 27935dad8f..2cad9e2e56 100644 --- a/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk @@ -2,5 +2,6 @@ MCU_SERIES = l4 CMSIS_MCU = STM32L476xx AF_FILE = boards/stm32l476_af.csv LD_FILES = boards/stm32l476xg.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 TEXT1_ADDR = 0x08004000 OPENOCD_CONFIG = boards/openocd_stm32l4.cfg From ddb3b84c70b2481e576a77277fda9b0601cf6b13 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 27 Mar 2018 21:29:45 +1100 Subject: [PATCH 486/828] stm32/boards: Add common_basic.ld for a board to have a single section. --- ports/stm32/boards/common_basic.ld | 86 ++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 ports/stm32/boards/common_basic.ld diff --git a/ports/stm32/boards/common_basic.ld b/ports/stm32/boards/common_basic.ld new file mode 100644 index 0000000000..2e428aa62c --- /dev/null +++ b/ports/stm32/boards/common_basic.ld @@ -0,0 +1,86 @@ +/* Memory layout for basic configuration: + + FLASH .isr_vector + FLASH .text + FLASH .data + + RAM .data + RAM .bss + RAM .heap + RAM .stack +*/ + +ENTRY(Reset_Handler) + +/* define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + + . = ALIGN(4); + } >FLASH + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text*) /* .text* sections (code) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + /* *(.glue_7) */ /* glue arm to thumb code */ + /* *(.glue_7t) */ /* glue thumb to arm code */ + + . = ALIGN(4); + _etext = .; /* define a global symbol at end of code */ + } >FLASH + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* This is the initialized data section + The program executes knowing that the data is in the RAM + but the loader puts the initial values in the FLASH (inidata). + It is one task of the startup to copy the initial values from FLASH to RAM. */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */ + } >RAM AT> FLASH + + /* Uninitialized data section */ + .bss : + { + . = ALIGN(4); + _sbss = .; /* define a global symbol at bss start; used by startup code */ + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end; used by startup code and GC */ + } >RAM + + /* this is to define the start of the heap, and make sure we have a minimum size */ + .heap : + { + . = ALIGN(4); + . = . + _minimum_heap_size; + . = ALIGN(4); + } >RAM + + /* this just checks there is enough RAM for the stack */ + .stack : + { + . = ALIGN(4); + . = . + _minimum_stack_size; + . = ALIGN(4); + } >RAM + + .ARM.attributes 0 : { *(.ARM.attributes) } +} From dcf4eb8134f7392d462e1a4d9f3db7cb8e62517e Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 27 Mar 2018 21:30:45 +1100 Subject: [PATCH 487/828] stm32/boards: Add common_bl.ld for boards that need a bootloader. --- ports/stm32/boards/common_bl.ld | 86 +++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 ports/stm32/boards/common_bl.ld diff --git a/ports/stm32/boards/common_bl.ld b/ports/stm32/boards/common_bl.ld new file mode 100644 index 0000000000..52b2a677d7 --- /dev/null +++ b/ports/stm32/boards/common_bl.ld @@ -0,0 +1,86 @@ +/* Memory layout for bootloader configuration (this here describes the app part): + + FLASH_APP .isr_vector + FLASH_APP .text + FLASH_APP .data + + RAM .data + RAM .bss + RAM .heap + RAM .stack +*/ + +ENTRY(Reset_Handler) + +/* define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + + . = ALIGN(4); + } >FLASH_APP + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text*) /* .text* sections (code) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + /* *(.glue_7) */ /* glue arm to thumb code */ + /* *(.glue_7t) */ /* glue thumb to arm code */ + + . = ALIGN(4); + _etext = .; /* define a global symbol at end of code */ + } >FLASH_APP + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* This is the initialized data section + The program executes knowing that the data is in the RAM + but the loader puts the initial values in the FLASH (inidata). + It is one task of the startup to copy the initial values from FLASH to RAM. */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */ + } >RAM AT> FLASH_APP + + /* Uninitialized data section */ + .bss : + { + . = ALIGN(4); + _sbss = .; /* define a global symbol at bss start; used by startup code */ + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end; used by startup code and GC */ + } >RAM + + /* this is to define the start of the heap, and make sure we have a minimum size */ + .heap : + { + . = ALIGN(4); + . = . + _minimum_heap_size; + . = ALIGN(4); + } >RAM + + /* this just checks there is enough RAM for the stack */ + .stack : + { + . = ALIGN(4); + . = . + _minimum_stack_size; + . = ALIGN(4); + } >RAM + + .ARM.attributes 0 : { *(.ARM.attributes) } +} From 04de9e33bce3c30de86c3486a132f5a646239c4a Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 27 Mar 2018 21:32:39 +1100 Subject: [PATCH 488/828] stm32/system_stm32: Set VTOR pointer from TEXT0_ADDR. --- ports/stm32/Makefile | 1 + ports/stm32/system_stm32.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index d1c5de6d33..66582058aa 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -72,6 +72,7 @@ CFLAGS += $(CFLAGS_MCU_$(MCU_SERIES)) CFLAGS += $(COPT) CFLAGS += -Iboards/$(BOARD) CFLAGS += -DSTM32_HAL_H='' +CFLAGS += -DMICROPY_HW_VTOR=$(TEXT0_ADDR) ifeq ($(MICROPY_FLOAT_IMPL),double) CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_DOUBLE diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c index 6c24ee417b..251902259e 100644 --- a/ports/stm32/system_stm32.c +++ b/ports/stm32/system_stm32.c @@ -275,10 +275,14 @@ void SystemInit(void) #endif /* Configure the Vector Table location add offset address ------------------*/ +#ifdef MICROPY_HW_VTOR + SCB->VTOR = MICROPY_HW_VTOR; +#else #ifdef VECT_TAB_SRAM SCB->VTOR = SRAM1_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */ #else SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */ +#endif #endif /* dpgeorge: enable 8-byte stack alignment for IRQ handlers, in accord with EABI */ From 4d409b8e3276c2e40191ada9726780a0dcc776ba Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 27 Mar 2018 21:35:03 +1100 Subject: [PATCH 489/828] stm32/boards/stm32f767.ld: Add definition of FLASH_APP. This allows F767 MCUs to support a bootloader in the first sector. --- ports/stm32/boards/stm32f767.ld | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm32/boards/stm32f767.ld b/ports/stm32/boards/stm32f767.ld index 7e34a90d52..c05fd8021b 100644 --- a/ports/stm32/boards/stm32f767.ld +++ b/ports/stm32/boards/stm32f767.ld @@ -7,6 +7,7 @@ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 32K /* sector 0, 32K */ + FLASH_APP (rx) : ORIGIN = 0x08008000, LENGTH = 2016K /* sectors 1-11 3x32K 1*128K 7*256K */ FLASH_FS (r) : ORIGIN = 0x08008000, LENGTH = 96K /* sectors 1, 2, 3 (32K each) */ FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 896K /* sectors 4-7 1*128Kib 3*256KiB = 896K */ DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* Used for storage cache */ From b121c9515d60347b227e22faa8c54474a329a9e0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 28 Mar 2018 13:20:07 +1100 Subject: [PATCH 490/828] stm32/boards/stm32h743.ld: Remove include of common.ld. The relevant common.ld file should now be included explicitly by a particular board. --- ports/stm32/boards/stm32h743.ld | 3 --- 1 file changed, 3 deletions(-) diff --git a/ports/stm32/boards/stm32h743.ld b/ports/stm32/boards/stm32h743.ld index 63c160c862..77bbfacb10 100644 --- a/ports/stm32/boards/stm32h743.ld +++ b/ports/stm32/boards/stm32h743.ld @@ -22,9 +22,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); From 1efe6a0316a08896f25730e2ca8f6c32417d7306 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 28 Mar 2018 13:20:48 +1100 Subject: [PATCH 491/828] stm32/boards/NUCLEO_H743ZI: Update to build with new linker management. --- ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk index 82b12cd2da..4d3455441f 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk @@ -2,5 +2,6 @@ MCU_SERIES = h7 CMSIS_MCU = STM32H743xx MICROPY_FLOAT_IMPL = double AF_FILE = boards/stm32h743_af.csv -LD_FILE = boards/stm32h743.ld -TEXT_ADDR = 0x08040000 +LD_FILES = boards/stm32h743.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08040000 From 9b9896b44d3784896ac8ca64bc1746956c122f6a Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Thu, 22 Mar 2018 03:49:59 +0200 Subject: [PATCH 492/828] stm32/dma: Remove H7 SDMMC DMA descriptors. The H7 SD peripheral has direct connection to MDMA instead. --- ports/stm32/dma.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index 137f4bf428..b0efd2a938 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -89,7 +89,7 @@ static const DMA_InitTypeDef dma_init_struct_spi_i2c = { #endif }; -#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD +#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD && !defined(STM32H7) // Parameters to dma_init() for SDIO tx and rx. static const DMA_InitTypeDef dma_init_struct_sdio = { #if defined(STM32F4) || defined(STM32F7) @@ -344,26 +344,14 @@ const dma_descr_t dma_I2C_1_TX = { DMA1_Stream7, DMA_REQUEST_I2C1_TX, DMA_MEMORY const dma_descr_t dma_I2C_2_TX = { DMA1_Stream7, DMA_REQUEST_I2C2_TX, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c }; // DMA2 streams -#if defined(SDMMC2) && MICROPY_HW_HAS_SDCARD -const dma_descr_t dma_SDMMC_2_RX= { DMA2_Stream0, DMA_CHANNEL_11, DMA_PERIPH_TO_MEMORY, dma_id_8, &dma_init_struct_sdio }; -#endif const dma_descr_t dma_SPI_1_RX = { DMA2_Stream2, DMA_REQUEST_SPI1_RX, DMA_PERIPH_TO_MEMORY, dma_id_10, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_5_RX = { DMA2_Stream3, DMA_REQUEST_SPI5_RX, DMA_PERIPH_TO_MEMORY, dma_id_11, &dma_init_struct_spi_i2c }; -#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD -const dma_descr_t dma_SDIO_0_RX= { DMA2_Stream3, DMA_CHANNEL_4, DMA_PERIPH_TO_MEMORY, dma_id_11, &dma_init_struct_sdio }; -#endif const dma_descr_t dma_SPI_4_RX = { DMA2_Stream3, DMA_REQUEST_SPI4_RX, DMA_PERIPH_TO_MEMORY, dma_id_11, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_5_TX = { DMA2_Stream4, DMA_REQUEST_SPI5_TX, DMA_MEMORY_TO_PERIPH, dma_id_12, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_4_TX = { DMA2_Stream4, DMA_REQUEST_SPI4_TX, DMA_MEMORY_TO_PERIPH, dma_id_12, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_6_TX = { DMA2_Stream5, BDMA_REQUEST_SPI6_TX, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_1_TX = { DMA2_Stream5, DMA_REQUEST_SPI1_TX, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_spi_i2c }; -#if defined(SDMMC2) && MICROPY_HW_HAS_SDCARD -const dma_descr_t dma_SDMMC_2_TX= { DMA2_Stream5, DMA_CHANNEL_11, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_sdio }; -#endif const dma_descr_t dma_SPI_6_RX = { DMA2_Stream6, BDMA_REQUEST_SPI6_RX, DMA_PERIPH_TO_MEMORY, dma_id_14, &dma_init_struct_spi_i2c }; -#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD -const dma_descr_t dma_SDIO_0_TX= { DMA2_Stream6, DMA_CHANNEL_4, DMA_MEMORY_TO_PERIPH, dma_id_14, &dma_init_struct_sdio }; -#endif static const uint8_t dma_irqn[NSTREAM] = { DMA1_Stream0_IRQn, From b4f814c9b75939a33caa769e87b8d1e9c82227f3 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Sat, 24 Mar 2018 21:23:35 +0200 Subject: [PATCH 493/828] stm32/sdcard: Add H7 SD card support. --- ports/stm32/sdcard.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index 9d5ef0e1c3..47a274775b 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -39,7 +39,7 @@ #if MICROPY_HW_HAS_SDCARD -#if defined(STM32F7) || defined(STM32L4) +#if defined(STM32F7) || defined(STM32H7) || defined(STM32L4) // The F7 has 2 SDMMC units but at the moment we only support using one of them in // a given build. If a boards config file defines MICROPY_HW_SDMMC2_CK then SDMMC2 @@ -80,7 +80,15 @@ #define SDIO_HARDWARE_FLOW_CONTROL_DISABLE SDMMC_HARDWARE_FLOW_CONTROL_DISABLE #define SDIO_HARDWARE_FLOW_CONTROL_ENABLE SDMMC_HARDWARE_FLOW_CONTROL_ENABLE +#if defined(STM32H7) +#define GPIO_AF12_SDIO GPIO_AF12_SDIO1 +#define SDIO_IRQHandler SDMMC1_IRQHandler +#define SDIO_TRANSFER_CLK_DIV SDMMC_NSpeed_CLK_DIV +#define SDIO_USE_GPDMA 0 +#else #define SDIO_TRANSFER_CLK_DIV SDMMC_TRANSFER_CLK_DIV +#define SDIO_USE_GPDMA 1 +#endif #else @@ -91,6 +99,7 @@ #define SDMMC_IRQn SDIO_IRQn #define SDMMC_TX_DMA dma_SDIO_0_TX #define SDMMC_RX_DMA dma_SDIO_0_RX +#define SDIO_USE_GPDMA 1 #endif @@ -116,7 +125,9 @@ // if an sd card is detected. This will save approx 260 bytes of RAM // when no sdcard was being used. static SD_HandleTypeDef sd_handle; +#if SDIO_USE_GPDMA static DMA_HandleTypeDef sd_rx_dma, sd_tx_dma; +#endif void sdcard_init(void) { // invalidate the sd_handle @@ -155,6 +166,12 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { // enable SDIO clock SDMMC_CLK_ENABLE(); + #if defined(STM32H7) + // Reset SDMMC + __HAL_RCC_SDMMC1_FORCE_RESET(); + __HAL_RCC_SDMMC1_RELEASE_RESET(); + #endif + // NVIC configuration for SDIO interrupts HAL_NVIC_SetPriority(SDMMC_IRQn, IRQ_PRI_SDIO, IRQ_SUBPRI_SDIO); HAL_NVIC_EnableIRQ(SDMMC_IRQn); @@ -182,7 +199,9 @@ bool sdcard_power_on(void) { // SD device interface configuration sd_handle.Instance = SDIO; sd_handle.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; + #ifndef STM32H7 sd_handle.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; + #endif sd_handle.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_ENABLE; sd_handle.Init.BusWide = SDIO_BUS_WIDE_1B; sd_handle.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; @@ -310,8 +329,10 @@ mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blo // we must disable USB irqs to prevent MSC contention with SD card uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); + #if SDIO_USE_GPDMA dma_init(&sd_rx_dma, &SDMMC_RX_DMA, &sd_handle); sd_handle.hdmarx = &sd_rx_dma; + #endif // make sure cache is flushed and invalidated so when DMA updates the RAM // from reading the peripheral the CPU then reads the new data @@ -322,8 +343,10 @@ mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blo err = sdcard_wait_finished(&sd_handle, 60000); } + #if SDIO_USE_GPDMA dma_deinit(&SDMMC_RX_DMA); sd_handle.hdmarx = NULL; + #endif restore_irq_pri(basepri); } else { @@ -372,8 +395,10 @@ mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t n // we must disable USB irqs to prevent MSC contention with SD card uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); + #if SDIO_USE_GPDMA dma_init(&sd_tx_dma, &SDMMC_TX_DMA, &sd_handle); sd_handle.hdmatx = &sd_tx_dma; + #endif // make sure cache is flushed to RAM so the DMA can read the correct data MP_HAL_CLEAN_DCACHE(src, num_blocks * SDCARD_BLOCK_SIZE); @@ -382,8 +407,11 @@ mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t n if (err == HAL_OK) { err = sdcard_wait_finished(&sd_handle, 60000); } + + #if SDIO_USE_GPDMA dma_deinit(&SDMMC_TX_DMA); sd_handle.hdmatx = NULL; + #endif restore_irq_pri(basepri); } else { From cf1d6df05acc22b641fb97de6a87b100b4fcfcb1 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Sat, 24 Mar 2018 21:24:06 +0200 Subject: [PATCH 494/828] stm32/boards/NUCLEO_H743ZI: Enable SD card support. --- ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h | 6 ++++++ ports/stm32/boards/NUCLEO_H743ZI/pins.csv | 14 +++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h index 9642061371..7aea8b06a6 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h @@ -6,6 +6,7 @@ #define MICROPY_HW_ENABLE_USB (1) #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_BOARD_EARLY_INIT NUCLEO_H743ZI_board_early_init void NUCLEO_H743ZI_board_early_init(void); @@ -55,3 +56,8 @@ void NUCLEO_H743ZI_board_early_init(void); #define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) + +// SD card detect switch +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_G2) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) diff --git a/ports/stm32/boards/NUCLEO_H743ZI/pins.csv b/ports/stm32/boards/NUCLEO_H743ZI/pins.csv index 82f80764f7..92627ba957 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/pins.csv +++ b/ports/stm32/boards/NUCLEO_H743ZI/pins.csv @@ -35,13 +35,13 @@ I2C1_SCL,PB8 I2C2_SDA,PF0 I2C2_SCL,PF1 EXT_RST,PG3 -SD_D0,PG9 -SD_D1,PG10 -SD_D2,PB3 -SD_D3,PB4 -SD_CK,PD6 -SD_CMD,PD7 -SD_SW,PI15 +SD_D0,PC8 +SD_D1,PC9 +SD_D2,PC10 +SD_D3,PC11 +SD_CMD,PD2 +SD_CK,PC12 +SD_SW,PG2 LCD_BL_CTRL,PK3 LCD_INT,PI13 LCD_SDA,PH8 From 2dca693c24f9bcadb1e06113848fff620d8088dd Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 28 Mar 2018 16:13:21 +1100 Subject: [PATCH 495/828] stm32: Change pin_X and pyb_pin_X identifiers to be pointers to objects. Rather than pin objects themselves. The actual object is now pin_X_obj and defines are provided so that pin_X is &pin_X_obj. This makes it so that code that uses pin objects doesn't need to know if they are literals or objects (that need pointers taken) or something else. They are just entities that can be passed to the map_hal_pin_xxx functions. This mirrors how the core handles constant objects (eg mp_const_none which is &mp_const_none_obj) and allows for the possibility of different implementations of the pin layer. For example, prior to this patch there was the following: extern const pin_obj_t pin_A0; #define pyb_pin_X1 pin_A0 ... mp_hal_pin_high(&pin_A0); and now there is: extern const pin_obj_t pin_A0_obj; #define pin_A0 (&pin_A0_obj) #define pyb_pin_X1 pin_A0 ... mp_hal_pin_high(pin_A0); This patch should have minimal effect on board configuration files. The only change that may be needed is if a board has .c files that configure pins. --- ports/stm32/accel.c | 8 +++--- ports/stm32/boards/make-pins.py | 14 +++++----- ports/stm32/dac.c | 4 +-- ports/stm32/i2c.c | 16 +++++------ ports/stm32/lcd.c | 16 +++++------ ports/stm32/led.c | 8 +++--- ports/stm32/machine_i2c.c | 8 +++--- ports/stm32/sdcard.c | 28 +++++++++---------- ports/stm32/servo.c | 16 +++++------ ports/stm32/spi.c | 48 ++++++++++++++++----------------- ports/stm32/uart.c | 44 +++++++++++++++--------------- ports/stm32/usrsw.c | 6 ++--- 12 files changed, 108 insertions(+), 108 deletions(-) diff --git a/ports/stm32/accel.c b/ports/stm32/accel.c index 8d61fb88d0..ec76727824 100644 --- a/ports/stm32/accel.c +++ b/ports/stm32/accel.c @@ -56,8 +56,8 @@ void accel_init(void) { // PB5 is connected to AVDD; pull high to enable MMA accel device - mp_hal_pin_low(&MICROPY_HW_MMA_AVDD_PIN); // turn off AVDD - mp_hal_pin_output(&MICROPY_HW_MMA_AVDD_PIN); + mp_hal_pin_low(MICROPY_HW_MMA_AVDD_PIN); // turn off AVDD + mp_hal_pin_output(MICROPY_HW_MMA_AVDD_PIN); } STATIC void accel_start(void) { @@ -73,9 +73,9 @@ STATIC void accel_start(void) { i2c_init(&I2CHandle1); // turn off AVDD, wait 30ms, turn on AVDD, wait 30ms again - mp_hal_pin_low(&MICROPY_HW_MMA_AVDD_PIN); // turn off + mp_hal_pin_low(MICROPY_HW_MMA_AVDD_PIN); // turn off mp_hal_delay_ms(30); - mp_hal_pin_high(&MICROPY_HW_MMA_AVDD_PIN); // turn on + mp_hal_pin_high(MICROPY_HW_MMA_AVDD_PIN); // turn on mp_hal_delay_ms(30); HAL_StatusTypeDef status; diff --git a/ports/stm32/boards/make-pins.py b/ports/stm32/boards/make-pins.py index 7db174114a..c9f6516f1c 100755 --- a/ports/stm32/boards/make-pins.py +++ b/ports/stm32/boards/make-pins.py @@ -207,18 +207,18 @@ class Pin(object): print("// ", end='') print('};') print('') - print('const pin_obj_t pin_{:s} = PIN({:s}, {:d}, {:s}, {:s}, {:d});'.format( + print('const pin_obj_t pin_{:s}_obj = PIN({:s}, {:d}, {:s}, {:s}, {:d});'.format( self.cpu_pin_name(), self.port_letter(), self.pin, self.alt_fn_name(null_if_0=True), self.adc_num_str(), self.adc_channel)) print('') def print_header(self, hdr_file): - hdr_file.write('extern const pin_obj_t pin_{:s};\n'. - format(self.cpu_pin_name())) + n = self.cpu_pin_name() + hdr_file.write('extern const pin_obj_t pin_{:s}_obj;\n'.format(n)) + hdr_file.write('#define pin_{:s} (&pin_{:s}_obj)\n'.format(n, n)) if self.alt_fn_count > 0: - hdr_file.write('extern const pin_af_obj_t pin_{:s}_af[];\n'. - format(self.cpu_pin_name())) + hdr_file.write('extern const pin_af_obj_t pin_{:s}_af[];\n'.format(n)) def qstr_list(self): result = [] @@ -287,7 +287,7 @@ class Pins(object): for named_pin in named_pins: pin = named_pin.pin() if pin.is_board_pin(): - print(' {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&pin_{:s}) }},'.format(named_pin.name(), pin.cpu_pin_name())) + print(' {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&pin_{:s}_obj) }},'.format(named_pin.name(), pin.cpu_pin_name())) print('};') print('MP_DEFINE_CONST_DICT(pin_{:s}_pins_locals_dict, pin_{:s}_pins_locals_dict_table);'.format(label, label)); @@ -311,7 +311,7 @@ class Pins(object): pin = named_pin.pin() if (pin.is_board_pin() and (pin.adc_num & (1 << (adc_num - 1))) and (pin.adc_channel == channel)): - print(' &pin_{:s}, // {:d}'.format(pin.cpu_pin_name(), channel)) + print(' &pin_{:s}_obj, // {:d}'.format(pin.cpu_pin_name(), channel)) adc_found = True break if not adc_found: diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c index 09a86f94c8..9d8d7a872f 100644 --- a/ports/stm32/dac.c +++ b/ports/stm32/dac.c @@ -212,9 +212,9 @@ STATIC mp_obj_t pyb_dac_make_new(const mp_obj_type_t *type, size_t n_args, size_ dac_id = mp_obj_get_int(args[0]); } else { const pin_obj_t *pin = pin_find(args[0]); - if (pin == &pin_A4) { + if (pin == pin_A4) { dac_id = 1; - } else if (pin == &pin_A5) { + } else if (pin == pin_A5) { dac_id = 2; } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Pin(%q) doesn't have DAC capabilities", pin->name)); diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index 65a88551e3..d4f6080077 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -260,29 +260,29 @@ void i2c_init(I2C_HandleTypeDef *i2c) { #if defined(MICROPY_HW_I2C1_SCL) } else if (i2c == &I2CHandle1) { i2c_unit = 1; - scl_pin = &MICROPY_HW_I2C1_SCL; - sda_pin = &MICROPY_HW_I2C1_SDA; + scl_pin = MICROPY_HW_I2C1_SCL; + sda_pin = MICROPY_HW_I2C1_SDA; __I2C1_CLK_ENABLE(); #endif #if defined(MICROPY_HW_I2C2_SCL) } else if (i2c == &I2CHandle2) { i2c_unit = 2; - scl_pin = &MICROPY_HW_I2C2_SCL; - sda_pin = &MICROPY_HW_I2C2_SDA; + scl_pin = MICROPY_HW_I2C2_SCL; + sda_pin = MICROPY_HW_I2C2_SDA; __I2C2_CLK_ENABLE(); #endif #if defined(MICROPY_HW_I2C3_SCL) } else if (i2c == &I2CHandle3) { i2c_unit = 3; - scl_pin = &MICROPY_HW_I2C3_SCL; - sda_pin = &MICROPY_HW_I2C3_SDA; + scl_pin = MICROPY_HW_I2C3_SCL; + sda_pin = MICROPY_HW_I2C3_SDA; __I2C3_CLK_ENABLE(); #endif #if defined(MICROPY_HW_I2C4_SCL) } else if (i2c == &I2CHandle4) { i2c_unit = 4; - scl_pin = &MICROPY_HW_I2C4_SCL; - sda_pin = &MICROPY_HW_I2C4_SDA; + scl_pin = MICROPY_HW_I2C4_SCL; + sda_pin = MICROPY_HW_I2C4_SDA; __I2C4_CLK_ENABLE(); #endif } else { diff --git a/ports/stm32/lcd.c b/ports/stm32/lcd.c index c88ffd4f94..10fb54eb5f 100644 --- a/ports/stm32/lcd.c +++ b/ports/stm32/lcd.c @@ -207,16 +207,16 @@ STATIC mp_obj_t pyb_lcd_make_new(const mp_obj_type_t *type, size_t n_args, size_ // TODO accept an SPI object and pin objects for full customisation if ((lcd_id[0] | 0x20) == 'x' && lcd_id[1] == '\0') { lcd->spi = &spi_obj[0]; - lcd->pin_cs1 = &pyb_pin_X3; - lcd->pin_rst = &pyb_pin_X4; - lcd->pin_a0 = &pyb_pin_X5; - lcd->pin_bl = &pyb_pin_X12; + lcd->pin_cs1 = pyb_pin_X3; + lcd->pin_rst = pyb_pin_X4; + lcd->pin_a0 = pyb_pin_X5; + lcd->pin_bl = pyb_pin_X12; } else if ((lcd_id[0] | 0x20) == 'y' && lcd_id[1] == '\0') { lcd->spi = &spi_obj[1]; - lcd->pin_cs1 = &pyb_pin_Y3; - lcd->pin_rst = &pyb_pin_Y4; - lcd->pin_a0 = &pyb_pin_Y5; - lcd->pin_bl = &pyb_pin_Y12; + lcd->pin_cs1 = pyb_pin_Y3; + lcd->pin_rst = pyb_pin_Y4; + lcd->pin_a0 = pyb_pin_Y5; + lcd->pin_bl = pyb_pin_Y12; } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "LCD(%s) doesn't exist", lcd_id)); } diff --git a/ports/stm32/led.c b/ports/stm32/led.c index a95d6c1a4b..6586f92131 100644 --- a/ports/stm32/led.c +++ b/ports/stm32/led.c @@ -51,13 +51,13 @@ typedef struct _pyb_led_obj_t { } pyb_led_obj_t; STATIC const pyb_led_obj_t pyb_led_obj[] = { - {{&pyb_led_type}, 1, &MICROPY_HW_LED1}, + {{&pyb_led_type}, 1, MICROPY_HW_LED1}, #if defined(MICROPY_HW_LED2) - {{&pyb_led_type}, 2, &MICROPY_HW_LED2}, + {{&pyb_led_type}, 2, MICROPY_HW_LED2}, #if defined(MICROPY_HW_LED3) - {{&pyb_led_type}, 3, &MICROPY_HW_LED3}, + {{&pyb_led_type}, 3, MICROPY_HW_LED3}, #if defined(MICROPY_HW_LED4) - {{&pyb_led_type}, 4, &MICROPY_HW_LED4}, + {{&pyb_led_type}, 4, MICROPY_HW_LED4}, #endif #endif #endif diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c index 33da4e57e0..8fc6c2a1ed 100644 --- a/ports/stm32/machine_i2c.c +++ b/ports/stm32/machine_i2c.c @@ -424,22 +424,22 @@ typedef mp_machine_soft_i2c_obj_t machine_hard_i2c_obj_t; STATIC machine_hard_i2c_obj_t machine_hard_i2c_obj[] = { #if defined(MICROPY_HW_I2C1_SCL) - {{&machine_hard_i2c_type}, 1, 500, &MICROPY_HW_I2C1_SCL, &MICROPY_HW_I2C1_SDA}, + {{&machine_hard_i2c_type}, 1, 500, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA}, #else {{NULL}, 0, 0, NULL, NULL}, #endif #if defined(MICROPY_HW_I2C2_SCL) - {{&machine_hard_i2c_type}, 1, 500, &MICROPY_HW_I2C2_SCL, &MICROPY_HW_I2C2_SDA}, + {{&machine_hard_i2c_type}, 1, 500, MICROPY_HW_I2C2_SCL, MICROPY_HW_I2C2_SDA}, #else {{NULL}, 0, 0, NULL, NULL}, #endif #if defined(MICROPY_HW_I2C3_SCL) - {{&machine_hard_i2c_type}, 1, 500, &MICROPY_HW_I2C3_SCL, &MICROPY_HW_I2C3_SDA}, + {{&machine_hard_i2c_type}, 1, 500, MICROPY_HW_I2C3_SCL, MICROPY_HW_I2C3_SDA}, #else {{NULL}, 0, 0, NULL, NULL}, #endif #if defined(MICROPY_HW_I2C4_SCL) - {{&machine_hard_i2c_type}, 1, 500, &MICROPY_HW_I2C4_SCL, &MICROPY_HW_I2C4_SDA}, + {{&machine_hard_i2c_type}, 1, 500, MICROPY_HW_I2C4_SCL, MICROPY_HW_I2C4_SDA}, #else {{NULL}, 0, 0, NULL, NULL}, #endif diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index 47a274775b..9244be5d4f 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -141,25 +141,25 @@ void sdcard_init(void) { // which clocks up to 25MHz maximum. #if defined(MICROPY_HW_SDMMC2_CK) // Use SDMMC2 peripheral with pins provided by the board's config - mp_hal_pin_config_alt(&MICROPY_HW_SDMMC2_CK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); - mp_hal_pin_config_alt(&MICROPY_HW_SDMMC2_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); - mp_hal_pin_config_alt(&MICROPY_HW_SDMMC2_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); - mp_hal_pin_config_alt(&MICROPY_HW_SDMMC2_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); - mp_hal_pin_config_alt(&MICROPY_HW_SDMMC2_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); - mp_hal_pin_config_alt(&MICROPY_HW_SDMMC2_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); + mp_hal_pin_config_alt(MICROPY_HW_SDMMC2_CK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); + mp_hal_pin_config_alt(MICROPY_HW_SDMMC2_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); + mp_hal_pin_config_alt(MICROPY_HW_SDMMC2_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); + mp_hal_pin_config_alt(MICROPY_HW_SDMMC2_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); + mp_hal_pin_config_alt(MICROPY_HW_SDMMC2_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); + mp_hal_pin_config_alt(MICROPY_HW_SDMMC2_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); #else // Default SDIO/SDMMC1 config - mp_hal_pin_config(&MICROPY_HW_SDMMC_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); - mp_hal_pin_config(&MICROPY_HW_SDMMC_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); - mp_hal_pin_config(&MICROPY_HW_SDMMC_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); - mp_hal_pin_config(&MICROPY_HW_SDMMC_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); - mp_hal_pin_config(&MICROPY_HW_SDMMC_CK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); - mp_hal_pin_config(&MICROPY_HW_SDMMC_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); + mp_hal_pin_config(MICROPY_HW_SDMMC_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); + mp_hal_pin_config(MICROPY_HW_SDMMC_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); + mp_hal_pin_config(MICROPY_HW_SDMMC_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); + mp_hal_pin_config(MICROPY_HW_SDMMC_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); + mp_hal_pin_config(MICROPY_HW_SDMMC_CK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); + mp_hal_pin_config(MICROPY_HW_SDMMC_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); #endif // configure the SD card detect pin // we do this here so we can detect if the SD card is inserted before powering it on - mp_hal_pin_config(&MICROPY_HW_SDCARD_DETECT_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_SDCARD_DETECT_PULL, 0); + mp_hal_pin_config(MICROPY_HW_SDCARD_DETECT_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_SDCARD_DETECT_PULL, 0); } void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { @@ -185,7 +185,7 @@ void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) { } bool sdcard_is_present(void) { - return HAL_GPIO_ReadPin(MICROPY_HW_SDCARD_DETECT_PIN.gpio, MICROPY_HW_SDCARD_DETECT_PIN.pin_mask) == MICROPY_HW_SDCARD_DETECT_PRESENT; + return HAL_GPIO_ReadPin(MICROPY_HW_SDCARD_DETECT_PIN->gpio, MICROPY_HW_SDCARD_DETECT_PIN->pin_mask) == MICROPY_HW_SDCARD_DETECT_PRESENT; } bool sdcard_power_on(void) { diff --git a/ports/stm32/servo.c b/ports/stm32/servo.c index 5e1c2762f7..966d2c688e 100644 --- a/ports/stm32/servo.c +++ b/ports/stm32/servo.c @@ -80,15 +80,15 @@ void servo_init(void) { // assign servo objects to specific pins (must be some permutation of PA0-PA3) #ifdef pyb_pin_X1 - pyb_servo_obj[0].pin = &pyb_pin_X1; - pyb_servo_obj[1].pin = &pyb_pin_X2; - pyb_servo_obj[2].pin = &pyb_pin_X3; - pyb_servo_obj[3].pin = &pyb_pin_X4; + pyb_servo_obj[0].pin = pyb_pin_X1; + pyb_servo_obj[1].pin = pyb_pin_X2; + pyb_servo_obj[2].pin = pyb_pin_X3; + pyb_servo_obj[3].pin = pyb_pin_X4; #else - pyb_servo_obj[0].pin = &pin_A0; - pyb_servo_obj[1].pin = &pin_A1; - pyb_servo_obj[2].pin = &pin_A2; - pyb_servo_obj[3].pin = &pin_A3; + pyb_servo_obj[0].pin = pin_A0; + pyb_servo_obj[1].pin = pin_A1; + pyb_servo_obj[2].pin = pin_A2; + pyb_servo_obj[3].pin = pin_A3; #endif } diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c index a8abebee49..a6e7143171 100644 --- a/ports/stm32/spi.c +++ b/ports/stm32/spi.c @@ -248,78 +248,78 @@ void spi_init(const spi_t *self, bool enable_nss_pin) { #if defined(MICROPY_HW_SPI1_SCK) } else if (spi->Instance == SPI1) { #if defined(MICROPY_HW_SPI1_NSS) - pins[0] = &MICROPY_HW_SPI1_NSS; + pins[0] = MICROPY_HW_SPI1_NSS; #endif - pins[1] = &MICROPY_HW_SPI1_SCK; + pins[1] = MICROPY_HW_SPI1_SCK; #if defined(MICROPY_HW_SPI1_MISO) - pins[2] = &MICROPY_HW_SPI1_MISO; + pins[2] = MICROPY_HW_SPI1_MISO; #endif - pins[3] = &MICROPY_HW_SPI1_MOSI; + pins[3] = MICROPY_HW_SPI1_MOSI; // enable the SPI clock __HAL_RCC_SPI1_CLK_ENABLE(); #endif #if defined(MICROPY_HW_SPI2_SCK) } else if (spi->Instance == SPI2) { #if defined(MICROPY_HW_SPI2_NSS) - pins[0] = &MICROPY_HW_SPI2_NSS; + pins[0] = MICROPY_HW_SPI2_NSS; #endif - pins[1] = &MICROPY_HW_SPI2_SCK; + pins[1] = MICROPY_HW_SPI2_SCK; #if defined(MICROPY_HW_SPI2_MISO) - pins[2] = &MICROPY_HW_SPI2_MISO; + pins[2] = MICROPY_HW_SPI2_MISO; #endif - pins[3] = &MICROPY_HW_SPI2_MOSI; + pins[3] = MICROPY_HW_SPI2_MOSI; // enable the SPI clock __HAL_RCC_SPI2_CLK_ENABLE(); #endif #if defined(MICROPY_HW_SPI3_SCK) } else if (spi->Instance == SPI3) { #if defined(MICROPY_HW_SPI3_NSS) - pins[0] = &MICROPY_HW_SPI3_NSS; + pins[0] = MICROPY_HW_SPI3_NSS; #endif - pins[1] = &MICROPY_HW_SPI3_SCK; + pins[1] = MICROPY_HW_SPI3_SCK; #if defined(MICROPY_HW_SPI3_MISO) - pins[2] = &MICROPY_HW_SPI3_MISO; + pins[2] = MICROPY_HW_SPI3_MISO; #endif - pins[3] = &MICROPY_HW_SPI3_MOSI; + pins[3] = MICROPY_HW_SPI3_MOSI; // enable the SPI clock __HAL_RCC_SPI3_CLK_ENABLE(); #endif #if defined(MICROPY_HW_SPI4_SCK) } else if (spi->Instance == SPI4) { #if defined(MICROPY_HW_SPI4_NSS) - pins[0] = &MICROPY_HW_SPI4_NSS; + pins[0] = MICROPY_HW_SPI4_NSS; #endif - pins[1] = &MICROPY_HW_SPI4_SCK; + pins[1] = MICROPY_HW_SPI4_SCK; #if defined(MICROPY_HW_SPI4_MISO) - pins[2] = &MICROPY_HW_SPI4_MISO; + pins[2] = MICROPY_HW_SPI4_MISO; #endif - pins[3] = &MICROPY_HW_SPI4_MOSI; + pins[3] = MICROPY_HW_SPI4_MOSI; // enable the SPI clock __HAL_RCC_SPI4_CLK_ENABLE(); #endif #if defined(MICROPY_HW_SPI5_SCK) } else if (spi->Instance == SPI5) { #if defined(MICROPY_HW_SPI5_NSS) - pins[0] = &MICROPY_HW_SPI5_NSS; + pins[0] = MICROPY_HW_SPI5_NSS; #endif - pins[1] = &MICROPY_HW_SPI5_SCK; + pins[1] = MICROPY_HW_SPI5_SCK; #if defined(MICROPY_HW_SPI5_MISO) - pins[2] = &MICROPY_HW_SPI5_MISO; + pins[2] = MICROPY_HW_SPI5_MISO; #endif - pins[3] = &MICROPY_HW_SPI5_MOSI; + pins[3] = MICROPY_HW_SPI5_MOSI; // enable the SPI clock __HAL_RCC_SPI5_CLK_ENABLE(); #endif #if defined(MICROPY_HW_SPI6_SCK) } else if (spi->Instance == SPI6) { #if defined(MICROPY_HW_SPI6_NSS) - pins[0] = &MICROPY_HW_SPI6_NSS; + pins[0] = MICROPY_HW_SPI6_NSS; #endif - pins[1] = &MICROPY_HW_SPI6_SCK; + pins[1] = MICROPY_HW_SPI6_SCK; #if defined(MICROPY_HW_SPI6_MISO) - pins[2] = &MICROPY_HW_SPI6_MISO; + pins[2] = MICROPY_HW_SPI6_MISO; #endif - pins[3] = &MICROPY_HW_SPI6_MOSI; + pins[3] = MICROPY_HW_SPI6_MOSI; // enable the SPI clock __HAL_RCC_SPI6_CLK_ENABLE(); #endif diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index bc52c9cc9c..a8b5d7dcae 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -181,8 +181,8 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { uart_unit = 1; UARTx = USART1; irqn = USART1_IRQn; - pins[0] = &MICROPY_HW_UART1_TX; - pins[1] = &MICROPY_HW_UART1_RX; + pins[0] = MICROPY_HW_UART1_TX; + pins[1] = MICROPY_HW_UART1_RX; __HAL_RCC_USART1_CLK_ENABLE(); break; #endif @@ -192,16 +192,16 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { uart_unit = 2; UARTx = USART2; irqn = USART2_IRQn; - pins[0] = &MICROPY_HW_UART2_TX; - pins[1] = &MICROPY_HW_UART2_RX; + pins[0] = MICROPY_HW_UART2_TX; + pins[1] = MICROPY_HW_UART2_RX; #if defined(MICROPY_HW_UART2_RTS) if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_RTS) { - pins[2] = &MICROPY_HW_UART2_RTS; + pins[2] = MICROPY_HW_UART2_RTS; } #endif #if defined(MICROPY_HW_UART2_CTS) if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) { - pins[3] = &MICROPY_HW_UART2_CTS; + pins[3] = MICROPY_HW_UART2_CTS; } #endif __HAL_RCC_USART2_CLK_ENABLE(); @@ -213,16 +213,16 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { uart_unit = 3; UARTx = USART3; irqn = USART3_IRQn; - pins[0] = &MICROPY_HW_UART3_TX; - pins[1] = &MICROPY_HW_UART3_RX; + pins[0] = MICROPY_HW_UART3_TX; + pins[1] = MICROPY_HW_UART3_RX; #if defined(MICROPY_HW_UART3_RTS) if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_RTS) { - pins[2] = &MICROPY_HW_UART3_RTS; + pins[2] = MICROPY_HW_UART3_RTS; } #endif #if defined(MICROPY_HW_UART3_CTS) if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) { - pins[3] = &MICROPY_HW_UART3_CTS; + pins[3] = MICROPY_HW_UART3_CTS; } #endif __HAL_RCC_USART3_CLK_ENABLE(); @@ -234,8 +234,8 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { uart_unit = 4; UARTx = UART4; irqn = UART4_IRQn; - pins[0] = &MICROPY_HW_UART4_TX; - pins[1] = &MICROPY_HW_UART4_RX; + pins[0] = MICROPY_HW_UART4_TX; + pins[1] = MICROPY_HW_UART4_RX; __HAL_RCC_UART4_CLK_ENABLE(); break; #endif @@ -245,8 +245,8 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { uart_unit = 5; UARTx = UART5; irqn = UART5_IRQn; - pins[0] = &MICROPY_HW_UART5_TX; - pins[1] = &MICROPY_HW_UART5_RX; + pins[0] = MICROPY_HW_UART5_TX; + pins[1] = MICROPY_HW_UART5_RX; __HAL_RCC_UART5_CLK_ENABLE(); break; #endif @@ -256,16 +256,16 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { uart_unit = 6; UARTx = USART6; irqn = USART6_IRQn; - pins[0] = &MICROPY_HW_UART6_TX; - pins[1] = &MICROPY_HW_UART6_RX; + pins[0] = MICROPY_HW_UART6_TX; + pins[1] = MICROPY_HW_UART6_RX; #if defined(MICROPY_HW_UART6_RTS) if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_RTS) { - pins[2] = &MICROPY_HW_UART6_RTS; + pins[2] = MICROPY_HW_UART6_RTS; } #endif #if defined(MICROPY_HW_UART6_CTS) if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) { - pins[3] = &MICROPY_HW_UART6_CTS; + pins[3] = MICROPY_HW_UART6_CTS; } #endif __HAL_RCC_USART6_CLK_ENABLE(); @@ -277,8 +277,8 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { uart_unit = 7; UARTx = UART7; irqn = UART7_IRQn; - pins[0] = &MICROPY_HW_UART7_TX; - pins[1] = &MICROPY_HW_UART7_RX; + pins[0] = MICROPY_HW_UART7_TX; + pins[1] = MICROPY_HW_UART7_RX; __HAL_RCC_UART7_CLK_ENABLE(); break; #endif @@ -288,8 +288,8 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { uart_unit = 8; UARTx = UART8; irqn = UART8_IRQn; - pins[0] = &MICROPY_HW_UART8_TX; - pins[1] = &MICROPY_HW_UART8_RX; + pins[0] = MICROPY_HW_UART8_TX; + pins[1] = MICROPY_HW_UART8_RX; __HAL_RCC_UART8_CLK_ENABLE(); break; #endif diff --git a/ports/stm32/usrsw.c b/ports/stm32/usrsw.c index 8b62210cb7..ded0b68640 100644 --- a/ports/stm32/usrsw.c +++ b/ports/stm32/usrsw.c @@ -53,11 +53,11 @@ // this function inits the switch GPIO so that it can be used void switch_init0(void) { - mp_hal_pin_config(&MICROPY_HW_USRSW_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_USRSW_PULL, 0); + mp_hal_pin_config(MICROPY_HW_USRSW_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_USRSW_PULL, 0); } int switch_get(void) { - int val = ((MICROPY_HW_USRSW_PIN.gpio->IDR & MICROPY_HW_USRSW_PIN.pin_mask) != 0); + int val = ((MICROPY_HW_USRSW_PIN->gpio->IDR & MICROPY_HW_USRSW_PIN->pin_mask) != 0); return val == MICROPY_HW_USRSW_PRESSED; } @@ -118,7 +118,7 @@ mp_obj_t pyb_switch_callback(mp_obj_t self_in, mp_obj_t callback) { // Init the EXTI each time this function is called, since the EXTI // may have been disabled by an exception in the interrupt, or the // user disabling the line explicitly. - extint_register((mp_obj_t)&MICROPY_HW_USRSW_PIN, + extint_register((mp_obj_t)MICROPY_HW_USRSW_PIN, MICROPY_HW_USRSW_EXTI_MODE, MICROPY_HW_USRSW_PULL, callback == mp_const_none ? mp_const_none : (mp_obj_t)&switch_callback_obj, From 7e28212352c390f2be78c2d020b41b88e665c09f Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 28 Mar 2018 16:22:43 +1100 Subject: [PATCH 496/828] stm32/boards/STM32L476DISC: Update to not take the address of pin objs. --- ports/stm32/boards/STM32L476DISC/bdev.c | 8 ++++---- ports/stm32/boards/STM32L476DISC/board_init.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ports/stm32/boards/STM32L476DISC/bdev.c b/ports/stm32/boards/STM32L476DISC/bdev.c index 0f7791033f..6b353a2f90 100644 --- a/ports/stm32/boards/STM32L476DISC/bdev.c +++ b/ports/stm32/boards/STM32L476DISC/bdev.c @@ -6,14 +6,14 @@ const mp_soft_spi_obj_t soft_spi_bus = { .delay_half = MICROPY_HW_SOFTSPI_MIN_DELAY, .polarity = 0, .phase = 0, - .sck = &MICROPY_HW_SPIFLASH_SCK, - .mosi = &MICROPY_HW_SPIFLASH_MOSI, - .miso = &MICROPY_HW_SPIFLASH_MISO, + .sck = MICROPY_HW_SPIFLASH_SCK, + .mosi = MICROPY_HW_SPIFLASH_MOSI, + .miso = MICROPY_HW_SPIFLASH_MISO, }; const mp_spiflash_config_t spiflash_config = { .bus_kind = MP_SPIFLASH_BUS_SPI, - .bus.u_spi.cs = &MICROPY_HW_SPIFLASH_CS, + .bus.u_spi.cs = MICROPY_HW_SPIFLASH_CS, .bus.u_spi.data = (void*)&soft_spi_bus, .bus.u_spi.proto = &mp_soft_spi_proto, }; diff --git a/ports/stm32/boards/STM32L476DISC/board_init.c b/ports/stm32/boards/STM32L476DISC/board_init.c index 30a6c309e0..eb44f320fe 100644 --- a/ports/stm32/boards/STM32L476DISC/board_init.c +++ b/ports/stm32/boards/STM32L476DISC/board_init.c @@ -2,8 +2,8 @@ void STM32L476DISC_board_early_init(void) { // set SPI flash WP and HOLD pins high - mp_hal_pin_output(&pin_E14); - mp_hal_pin_output(&pin_E15); - mp_hal_pin_write(&pin_E14, 1); - mp_hal_pin_write(&pin_E15, 1); + mp_hal_pin_output(pin_E14); + mp_hal_pin_output(pin_E15); + mp_hal_pin_write(pin_E14, 1); + mp_hal_pin_write(pin_E15, 1); } From d9e69681f5c100076aec5fb9a9ec00add3aa22b0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 29 Mar 2018 15:24:21 +1100 Subject: [PATCH 497/828] stm32: Add custom, optimised Reset_Handler code. The Reset_Handler needs to copy the data section and zero the BSS, and these operations should be as optimised as possible to reduce start up time. The versions provided in this patch are about 2x faster (on a Cortex M4) than the previous implementations. --- ports/stm32/Makefile | 1 + ports/stm32/resethandler.s | 66 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 ports/stm32/resethandler.s diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 66582058aa..0e7f7f71af 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -252,6 +252,7 @@ SRC_C = \ SRC_O = \ $(STARTUP_FILE) \ + resethandler.o \ gchelper.o \ SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ diff --git a/ports/stm32/resethandler.s b/ports/stm32/resethandler.s new file mode 100644 index 0000000000..6c37260dcb --- /dev/null +++ b/ports/stm32/resethandler.s @@ -0,0 +1,66 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + .syntax unified + .cpu cortex-m4 + .thumb + + .section .text.Reset_Handler + .global Reset_Handler + .type Reset_Handler, %function + +Reset_Handler: + /* Load the stack pointer */ + ldr sp, =_estack + + /* Initialise the data section */ + ldr r1, =_sidata + ldr r2, =_sdata + ldr r3, =_edata + b .data_copy_entry +.data_copy_loop: + ldr r0, [r1], #4 /* Should be 4-aligned to be as fast as possible */ + str r0, [r2], #4 +.data_copy_entry: + cmp r2, r3 + bcc .data_copy_loop + + /* Zero out the BSS section */ + movs r0, #0 + ldr r1, =_sbss + ldr r2, =_ebss + b .bss_zero_entry +.bss_zero_loop: + str r0, [r1], #4 /* Should be 4-aligned to be as fast as possible */ +.bss_zero_entry: + cmp r1, r2 + bcc .bss_zero_loop + + /* Initialise the system and jump to the main code */ + bl SystemInit + b main + + .size Reset_Handler, .-Reset_Handler From 7856a416bd4718dd2f63e3adcd8a595fb4fbb9e9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 29 Mar 2018 16:15:57 +1100 Subject: [PATCH 498/828] stm32/main: Rename main to stm32_main and pass through first argument. The main() function has a predefined type in C which is not so useful for embedded contexts. This patch renames main() to stm32_main() so we can define our own type signature for this function. The type signature is defined to have a single argument which is the "reset_mode" and is passed through as r0 from Reset_Handler. This allows, for example, a bootloader to pass through information into the main application. --- ports/stm32/main.c | 4 ++-- ports/stm32/resethandler.s | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index ccf490e36b..4b5997227c 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -413,7 +413,7 @@ STATIC uint update_reset_mode(uint reset_mode) { return reset_mode; } -int main(void) { +void stm32_main(uint32_t reset_mode) { // TODO disable JTAG /* STM32F4xx HAL library initialization: @@ -488,7 +488,7 @@ soft_reset: #endif led_state(3, 0); led_state(4, 0); - uint reset_mode = update_reset_mode(1); + reset_mode = update_reset_mode(1); // Python threading init #if MICROPY_PY_THREAD diff --git a/ports/stm32/resethandler.s b/ports/stm32/resethandler.s index 6c37260dcb..7f0973346e 100644 --- a/ports/stm32/resethandler.s +++ b/ports/stm32/resethandler.s @@ -33,6 +33,9 @@ .type Reset_Handler, %function Reset_Handler: + /* Save the first argument to pass through to stm32_main */ + mov r4, r0 + /* Load the stack pointer */ ldr sp, =_estack @@ -61,6 +64,7 @@ Reset_Handler: /* Initialise the system and jump to the main code */ bl SystemInit - b main + mov r0, r4 + b stm32_main .size Reset_Handler, .-Reset_Handler From b833f170c324bd7b9f0c1623d539fb301e7f09a6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 29 Mar 2018 16:16:58 +1100 Subject: [PATCH 499/828] stm32/main: Only update reset_mode if board doesn't use a bootloader. If the board is configured to use a bootloader then that bootloader will pass through the reset_mode. --- ports/stm32/main.c | 7 ++++++- ports/stm32/mpconfigboard_common.h | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 4b5997227c..fb3e843bba 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -338,6 +338,7 @@ STATIC bool init_sdcard_fs(void) { } #endif +#if !MICROPY_HW_USES_BOOTLOADER STATIC uint update_reset_mode(uint reset_mode) { #if MICROPY_HW_HAS_SWITCH if (switch_get()) { @@ -412,6 +413,7 @@ STATIC uint update_reset_mode(uint reset_mode) { #endif return reset_mode; } +#endif void stm32_main(uint32_t reset_mode) { // TODO disable JTAG @@ -478,7 +480,6 @@ void stm32_main(uint32_t reset_mode) { soft_reset: - // check if user switch held to select the reset mode #if defined(MICROPY_HW_LED2) led_state(1, 0); led_state(2, 1); @@ -488,7 +489,11 @@ soft_reset: #endif led_state(3, 0); led_state(4, 0); + + #if !MICROPY_HW_USES_BOOTLOADER + // check if user switch held to select the reset mode reset_mode = update_reset_mode(1); + #endif // Python threading init #if MICROPY_PY_THREAD diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index b876d5884a..d4b812331d 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -171,3 +171,5 @@ #define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size) #define MP_HAL_CLEAN_DCACHE(addr, size) #endif + +#define MICROPY_HW_USES_BOOTLOADER (MICROPY_HW_VTOR != 0x08000000) From bc3a5f191714f28bef95d9f87c24f7367c90d54a Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 29 Mar 2018 16:23:52 +1100 Subject: [PATCH 500/828] stm32/mphalport: Use MCU regs to detect if cycle counter is started. Instead of using a dedicated variable in RAM it's simpler to use the relevant bits in the DWT register. --- ports/stm32/mphalport.c | 5 +---- ports/stm32/mphalport.h | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c index 74906311eb..0108d90261 100644 --- a/ports/stm32/mphalport.c +++ b/ports/stm32/mphalport.c @@ -7,8 +7,6 @@ #include "usb.h" #include "uart.h" -bool mp_hal_ticks_cpu_enabled = false; - // this table converts from HAL_StatusTypeDef to POSIX errno const byte mp_hal_status_to_errno_table[4] = { [HAL_OK] = 0, @@ -90,7 +88,7 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { } void mp_hal_ticks_cpu_enable(void) { - if (!mp_hal_ticks_cpu_enabled) { + if (!(DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk)) { CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; #if defined(__CORTEX_M) && __CORTEX_M == 7 // on Cortex-M7 we must unlock the DWT before writing to its registers @@ -98,7 +96,6 @@ void mp_hal_ticks_cpu_enable(void) { #endif DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; - mp_hal_ticks_cpu_enabled = true; } } diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h index c3d280b408..2843a79cd4 100644 --- a/ports/stm32/mphalport.h +++ b/ports/stm32/mphalport.h @@ -15,10 +15,9 @@ void mp_hal_set_interrupt_char(int c); // -1 to disable #define mp_hal_quiet_timing_exit(irq_state) restore_irq_pri(irq_state) #define mp_hal_delay_us_fast(us) mp_hal_delay_us(us) -extern bool mp_hal_ticks_cpu_enabled; void mp_hal_ticks_cpu_enable(void); static inline mp_uint_t mp_hal_ticks_cpu(void) { - if (!mp_hal_ticks_cpu_enabled) { + if (!(DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk)) { mp_hal_ticks_cpu_enable(); } return DWT->CYCCNT; From 32807881954f106b9735de74fe984062a0815b81 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 30 Mar 2018 11:09:00 +1100 Subject: [PATCH 501/828] py/runtime: Check that keys in dicts passed as ** args are strings. Prior to this patch the code would crash if a key in a ** dict was anything other than a str or qstr. This is because mp_setup_code_state() assumes that keys in kwargs are qstrs (for efficiency). Thanks to @jepler for finding the bug. --- py/obj.h | 1 + py/objstr.c | 6 ++++++ py/runtime.c | 8 ++++---- tests/basics/fun_calldblstar.py | 5 +++++ 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/py/obj.h b/py/obj.h index 2779b3f861..80599966e2 100644 --- a/py/obj.h +++ b/py/obj.h @@ -720,6 +720,7 @@ qstr mp_obj_str_get_qstr(mp_obj_t self_in); // use this if you will anyway conve const char *mp_obj_str_get_str(mp_obj_t self_in); // use this only if you need the string to be null terminated const char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len); mp_obj_t mp_obj_str_intern(mp_obj_t str); +mp_obj_t mp_obj_str_intern_checked(mp_obj_t obj); void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t str_len, bool is_bytes); #if MICROPY_PY_BUILTINS_FLOAT diff --git a/py/objstr.c b/py/objstr.c index c42f38e75b..0b11533f82 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -2062,6 +2062,12 @@ mp_obj_t mp_obj_str_intern(mp_obj_t str) { return mp_obj_new_str_via_qstr((const char*)data, len); } +mp_obj_t mp_obj_str_intern_checked(mp_obj_t obj) { + size_t len; + const char *data = mp_obj_str_get_data(obj, &len); + return mp_obj_new_str_via_qstr((const char*)data, len); +} + mp_obj_t mp_obj_new_bytes(const byte* data, size_t len) { return mp_obj_new_str_copy(&mp_type_bytes, data, len); } diff --git a/py/runtime.c b/py/runtime.c index 54ec0d70b4..ca68fe982d 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -748,8 +748,8 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ if (MP_MAP_SLOT_IS_FILLED(map, i)) { // the key must be a qstr, so intern it if it's a string mp_obj_t key = map->table[i].key; - if (MP_OBJ_IS_TYPE(key, &mp_type_str)) { - key = mp_obj_str_intern(key); + if (!MP_OBJ_IS_QSTR(key)) { + key = mp_obj_str_intern_checked(key); } args2[args2_len++] = key; args2[args2_len++] = map->table[i].value; @@ -778,8 +778,8 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ } // the key must be a qstr, so intern it if it's a string - if (MP_OBJ_IS_TYPE(key, &mp_type_str)) { - key = mp_obj_str_intern(key); + if (!MP_OBJ_IS_QSTR(key)) { + key = mp_obj_str_intern_checked(key); } // get the value corresponding to the key diff --git a/tests/basics/fun_calldblstar.py b/tests/basics/fun_calldblstar.py index aae9828cf7..4a503698ff 100644 --- a/tests/basics/fun_calldblstar.py +++ b/tests/basics/fun_calldblstar.py @@ -6,6 +6,11 @@ def f(a, b): f(1, **{'b':2}) f(1, **{'b':val for val in range(1)}) +try: + f(1, **{len:2}) +except TypeError: + print('TypeError') + # test calling a method with keywords given by **dict class A: From f50b64cab58025e080f994147b75a8ffc55d2b35 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 30 Mar 2018 12:37:04 +1100 Subject: [PATCH 502/828] py/runtime: Be sure that non-intercepted thrown object is an exception. The VM expects that, if mp_resume() returns MP_VM_RETURN_EXCEPTION, then the returned value is an exception instance (eg to add a traceback to it). It's possible that a value passed to a generator's throw() is not an exception so must be explicitly checked for if the thrown value is not intercepted by the generator. Thanks to @jepler for finding the bug. --- py/runtime.c | 2 +- tests/basics/gen_yield_from_throw3.py | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/py/runtime.c b/py/runtime.c index ca68fe982d..219ec22dee 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1282,7 +1282,7 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th // will be propagated up. This behavior is approved by test_pep380.py // test_delegation_of_close_to_non_generator(), // test_delegating_throw_to_non_generator() - *ret_val = throw_value; + *ret_val = mp_make_raise_obj(throw_value); return MP_VM_RETURN_EXCEPTION; } } diff --git a/tests/basics/gen_yield_from_throw3.py b/tests/basics/gen_yield_from_throw3.py index 0f6c7c8429..85b6f71f99 100644 --- a/tests/basics/gen_yield_from_throw3.py +++ b/tests/basics/gen_yield_from_throw3.py @@ -28,3 +28,30 @@ print(g.throw(123)) g = gen() print(next(g)) print(g.throw(ZeroDivisionError)) + +# this user-defined generator doesn't have a throw() method +class Iter2: + def __iter__(self): + return self + + def __next__(self): + return 1 + +def gen2(): + yield from Iter2() + +# the thrown ValueError is not intercepted by the user class +g = gen2() +print(next(g)) +try: + g.throw(ValueError) +except: + print('ValueError') + +# the thrown 123 is not an exception so raises a TypeError +g = gen2() +print(next(g)) +try: + g.throw(123) +except TypeError: + print('TypeError') From bcfff4fc98a73c5ad9b7d3e338649955e861ada4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 30 Mar 2018 14:21:18 +1100 Subject: [PATCH 503/828] tests/basics/iter1.py: Add more tests for walking a user-defined iter. Some code in mp_iternext() was only tested by the native emitter, so the tests added here test this function using just the bytecode emitter. --- tests/basics/iter1.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/basics/iter1.py b/tests/basics/iter1.py index 9117dfd2b7..26e9a2ef25 100644 --- a/tests/basics/iter1.py +++ b/tests/basics/iter1.py @@ -68,3 +68,12 @@ except StopIteration: for i in myiter(32): print(i) + +# repeat some of the above tests but use tuple() to walk the iterator (tests mp_iternext) +print(tuple(myiter(5))) +print(tuple(myiter(12))) +print(tuple(myiter(32))) +try: + tuple(myiter(22)) +except TypeError: + print('raised TypeError') From c7f880eda38783817bd490b8f2f0b60412c3b73c Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 4 Apr 2018 00:46:31 +1000 Subject: [PATCH 504/828] py/vm: Don't do unnecessary updates of ip and sp variables. Neither the ip nor sp variables are used again after the execution of the RAISE_VARARGS opcode, so they don't need to be updated. --- py/vm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/py/vm.c b/py/vm.c index 2a8e3c990c..7b3a0b3241 100644 --- a/py/vm.c +++ b/py/vm.c @@ -1118,7 +1118,7 @@ unwind_return: ENTRY(MP_BC_RAISE_VARARGS): { MARK_EXC_IP_SELECTIVE(); - mp_uint_t unum = *ip++; + mp_uint_t unum = *ip; mp_obj_t obj; if (unum == 2) { mp_warning("exception chaining not supported"); @@ -1139,7 +1139,7 @@ unwind_return: RAISE(obj); } } else { - obj = POP(); + obj = TOP(); } obj = mp_make_raise_obj(obj); RAISE(obj); From bc36521386a2c608be06fa8a5bf110b050dd1052 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 4 Apr 2018 00:51:10 +1000 Subject: [PATCH 505/828] py/vm: Optimise handling of stackless mode when pystack is enabled. When pystack is enabled mp_obj_fun_bc_prepare_codestate() will always return a valid pointer, and if there is no more pystack available then it will raise an exception (a RuntimeError). So having pystack enabled with stackless enabled automatically gives strict stackless mode. There is therefore no need to have code for strict stackless mode when pystack is enabled, and this patch optimises the VM for such a case. --- py/vm.c | 78 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/py/vm.c b/py/vm.c index 7b3a0b3241..8abe65e43b 100644 --- a/py/vm.c +++ b/py/vm.c @@ -911,21 +911,22 @@ unwind_jump:; code_state->sp = sp; code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1); - if (new_state) { + #if !MICROPY_ENABLE_PYSTACK + if (new_state == NULL) { + // Couldn't allocate codestate on heap: in the strict case raise + // an exception, otherwise just fall through to stack allocation. + #if MICROPY_STACKLESS_STRICT + deep_recursion_error: + mp_raise_recursion_depth(); + #endif + } else + #endif + { new_state->prev = code_state; code_state = new_state; nlr_pop(); goto run_code_state; } - #if MICROPY_STACKLESS_STRICT - else { - deep_recursion_error: - mp_raise_recursion_depth(); - } - #else - // If we couldn't allocate codestate on heap, in - // non non-strict case fall thru to stack allocation. - #endif } #endif SET_TOP(mp_call_function_n_kw(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1)); @@ -956,20 +957,21 @@ unwind_jump:; // pystack is not enabled. For pystack, they are freed when code_state is. mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t)); #endif - if (new_state) { + #if !MICROPY_ENABLE_PYSTACK + if (new_state == NULL) { + // Couldn't allocate codestate on heap: in the strict case raise + // an exception, otherwise just fall through to stack allocation. + #if MICROPY_STACKLESS_STRICT + goto deep_recursion_error; + #endif + } else + #endif + { new_state->prev = code_state; code_state = new_state; nlr_pop(); goto run_code_state; } - #if MICROPY_STACKLESS_STRICT - else { - goto deep_recursion_error; - } - #else - // If we couldn't allocate codestate on heap, in - // non non-strict case fall thru to stack allocation. - #endif } #endif SET_TOP(mp_call_method_n_kw_var(false, unum, sp)); @@ -993,20 +995,21 @@ unwind_jump:; int adjust = (sp[1] == MP_OBJ_NULL) ? 0 : 1; mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, n_args + adjust, n_kw, sp + 2 - adjust); - if (new_state) { + #if !MICROPY_ENABLE_PYSTACK + if (new_state == NULL) { + // Couldn't allocate codestate on heap: in the strict case raise + // an exception, otherwise just fall through to stack allocation. + #if MICROPY_STACKLESS_STRICT + goto deep_recursion_error; + #endif + } else + #endif + { new_state->prev = code_state; code_state = new_state; nlr_pop(); goto run_code_state; } - #if MICROPY_STACKLESS_STRICT - else { - goto deep_recursion_error; - } - #else - // If we couldn't allocate codestate on heap, in - // non non-strict case fall thru to stack allocation. - #endif } #endif SET_TOP(mp_call_method_n_kw(unum & 0xff, (unum >> 8) & 0xff, sp)); @@ -1037,20 +1040,21 @@ unwind_jump:; // pystack is not enabled. For pystack, they are freed when code_state is. mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t)); #endif - if (new_state) { + #if !MICROPY_ENABLE_PYSTACK + if (new_state == NULL) { + // Couldn't allocate codestate on heap: in the strict case raise + // an exception, otherwise just fall through to stack allocation. + #if MICROPY_STACKLESS_STRICT + goto deep_recursion_error; + #endif + } else + #endif + { new_state->prev = code_state; code_state = new_state; nlr_pop(); goto run_code_state; } - #if MICROPY_STACKLESS_STRICT - else { - goto deep_recursion_error; - } - #else - // If we couldn't allocate codestate on heap, in - // non non-strict case fall thru to stack allocation. - #endif } #endif SET_TOP(mp_call_method_n_kw_var(true, unum, sp)); From 430efb044400ae191edc0d1a1654b875284313a7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 4 Apr 2018 01:43:16 +1000 Subject: [PATCH 506/828] tests/basics: Add test for use of return within try-except. The case of a return statement in the try suite of a try-except statement was previously only tested by builtin_compile.py, and only then in the part of this test which checked for the existence of the compile builtin. So this patch adds an explicit unit test for this case. --- tests/basics/try_return.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/basics/try_return.py diff --git a/tests/basics/try_return.py b/tests/basics/try_return.py new file mode 100644 index 0000000000..492c18d95c --- /dev/null +++ b/tests/basics/try_return.py @@ -0,0 +1,11 @@ +# test use of return with try-except + +def f(l, i): + try: + return l[i] + except IndexError: + print('IndexError') + return -1 + +print(f([1], 0)) +print(f([], 0)) From f684e9e1ab23cb04b0572745e9fe1c9dbfa0f126 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 4 Apr 2018 13:56:00 +1000 Subject: [PATCH 507/828] tests/basics/int_big1.py: Add test converting str with non-print chars. --- tests/basics/int_big1.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/basics/int_big1.py b/tests/basics/int_big1.py index 425bc21b67..4bf44eb187 100644 --- a/tests/basics/int_big1.py +++ b/tests/basics/int_big1.py @@ -75,6 +75,10 @@ try: print(int("123456789012345678901234567890abcdef")) except ValueError: print('ValueError'); +try: + print(int("123456789012345678901234567890\x01")) +except ValueError: + print('ValueError'); # test constant integer with more than 255 chars x = 0x84ce72aa8699df436059f052ac51b6398d2511e49631bcb7e71f89c499b9ee425dfbc13a5f6d408471b054f2655617cbbaf7937b7c80cd8865cf02c8487d30d2b0fbd8b2c4e102e16d828374bbc47b93852f212d5043c3ea720f086178ff798cc4f63f787b9c2e419efa033e7644ea7936f54462dc21a6c4580725f7f0e7d1aaaaaaa From 7d5c753b17a1c9cbb8124839af144d0b8b936abc Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 4 Apr 2018 13:57:22 +1000 Subject: [PATCH 508/828] tests/basics: Modify int-big tests to prevent constant folding. So that these tests test the runtime behaviour, not the compiler (which may be executed offline). --- tests/basics/int_big_rshift.py | 6 ++++-- tests/basics/int_big_xor.py | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/basics/int_big_rshift.py b/tests/basics/int_big_rshift.py index b2fecb36c9..e6e2a66993 100644 --- a/tests/basics/int_big_rshift.py +++ b/tests/basics/int_big_rshift.py @@ -3,5 +3,7 @@ print(i >> 1) print(i >> 1000) # result needs rounding up -print(-(1<<70) >> 80) -print(-0xffffffffffffffff >> 32) +i = -(1 << 70) +print(i >> 80) +i = -0xffffffffffffffff +print(i >> 32) diff --git a/tests/basics/int_big_xor.py b/tests/basics/int_big_xor.py index 318db45e60..cd1d9ae97f 100644 --- a/tests/basics/int_big_xor.py +++ b/tests/basics/int_big_xor.py @@ -19,7 +19,8 @@ print((-a) ^ (1 << 100)) print((-a) ^ (1 << 200)) print((-a) ^ a == 0) print(bool((-a) ^ a)) -print(-1 ^ 0xffffffffffffffff) # carry overflows to higher digit +i = -1 +print(i ^ 0xffffffffffffffff) # carry overflows to higher digit # test + - From a45a34ec313d0fb57e2fb1bbacf6e9209483bbe6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 4 Apr 2018 13:58:57 +1000 Subject: [PATCH 509/828] tests/stress: Add test to verify the GC can trace nested objects. --- tests/run-tests | 1 + tests/stress/gc_trace.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 tests/stress/gc_trace.py diff --git a/tests/run-tests b/tests/run-tests index 627fa40dac..ef2f4bc6a5 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -366,6 +366,7 @@ def run_tests(pyb, tests, args, base_path="."): skip_tests.add('micropython/heapalloc_traceback.py') # because native doesn't have proper traceback info skip_tests.add('micropython/heapalloc_iter.py') # requires generators skip_tests.add('micropython/schedule.py') # native code doesn't check pending events + skip_tests.add('stress/gc_trace.py') # requires yield for test_file in tests: test_file = test_file.replace('\\', '/') diff --git a/tests/stress/gc_trace.py b/tests/stress/gc_trace.py new file mode 100644 index 0000000000..72dc7b6276 --- /dev/null +++ b/tests/stress/gc_trace.py @@ -0,0 +1,17 @@ +# test that the GC can trace nested objects + +try: + import gc +except ImportError: + print("SKIP") + raise SystemExit + +# test a big shallow object pointing to many unique objects +lst = [[i] for i in range(200)] +gc.collect() +print(lst) + +# test a deep object +lst = [[[[[(i, j, k, l)] for i in range(3)] for j in range(3)] for k in range(3)] for l in range(3)] +gc.collect() +print(lst) From 323b5f7270ee0e3c9000c0fb0d5f74ec049337c2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 4 Apr 2018 14:23:25 +1000 Subject: [PATCH 510/828] py/modsys: Don't compile getsizeof function if feature is disabled. --- py/modsys.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/py/modsys.c b/py/modsys.c index 84a4eb0f47..609f8b454c 100644 --- a/py/modsys.c +++ b/py/modsys.c @@ -140,10 +140,12 @@ STATIC mp_obj_t mp_sys_exc_info(void) { MP_DEFINE_CONST_FUN_OBJ_0(mp_sys_exc_info_obj, mp_sys_exc_info); #endif +#if MICROPY_PY_SYS_GETSIZEOF STATIC mp_obj_t mp_sys_getsizeof(mp_obj_t obj) { return mp_unary_op(MP_UNARY_OP_SIZEOF, obj); } -MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_getsizeof_obj, mp_sys_getsizeof); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_getsizeof_obj, mp_sys_getsizeof); +#endif STATIC const mp_rom_map_elem_t mp_module_sys_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sys) }, From 3f420c0c27bd6daa5af39517925be55b9b9a9ab3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 4 Apr 2018 14:24:03 +1000 Subject: [PATCH 511/828] py: Don't include mp_optimise_value or opt_level() if compiler disabled. Without the compiler enabled the mp_optimise_value is unused, and the micropython.opt_level() function is not useful, so exclude these from the build to save RAM and code size. --- py/modmicropython.c | 4 ++++ py/mpstate.h | 2 ++ py/runtime.c | 2 ++ 3 files changed, 8 insertions(+) diff --git a/py/modmicropython.c b/py/modmicropython.c index 5cc7bdbe29..864d1a5c5b 100644 --- a/py/modmicropython.c +++ b/py/modmicropython.c @@ -35,6 +35,7 @@ // Various builtins specific to MicroPython runtime, // living in micropython module +#if MICROPY_ENABLE_COMPILER STATIC mp_obj_t mp_micropython_opt_level(size_t n_args, const mp_obj_t *args) { if (n_args == 0) { return MP_OBJ_NEW_SMALL_INT(MP_STATE_VM(mp_optimise_value)); @@ -44,6 +45,7 @@ STATIC mp_obj_t mp_micropython_opt_level(size_t n_args, const mp_obj_t *args) { } } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_opt_level_obj, 0, 1, mp_micropython_opt_level); +#endif #if MICROPY_PY_MICROPYTHON_MEM_INFO @@ -158,7 +160,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_micropython_schedule_obj, mp_micropython_sch STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_micropython) }, { MP_ROM_QSTR(MP_QSTR_const), MP_ROM_PTR(&mp_identity_obj) }, + #if MICROPY_ENABLE_COMPILER { MP_ROM_QSTR(MP_QSTR_opt_level), MP_ROM_PTR(&mp_micropython_opt_level_obj) }, + #endif #if MICROPY_PY_MICROPYTHON_MEM_INFO #if MICROPY_MEM_STATS { MP_ROM_QSTR(MP_QSTR_mem_total), MP_ROM_PTR(&mp_micropython_mem_total_obj) }, diff --git a/py/mpstate.h b/py/mpstate.h index 816698f4e2..16c4bf6c57 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -199,7 +199,9 @@ typedef struct _mp_state_vm_t { mp_thread_mutex_t qstr_mutex; #endif + #if MICROPY_ENABLE_COMPILER mp_uint_t mp_optimise_value; + #endif // size of the emergency exception buf, if it's dynamically allocated #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0 diff --git a/py/runtime.c b/py/runtime.c index 219ec22dee..4efb29bec7 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -83,8 +83,10 @@ void mp_init(void) { MICROPY_PORT_INIT_FUNC; #endif + #if MICROPY_ENABLE_COMPILER // optimization disabled by default MP_STATE_VM(mp_optimise_value) = 0; + #endif // init global module dict mp_obj_dict_init(&MP_STATE_VM(mp_loaded_modules_dict), 3); From df02f5620ab32c4ae03f2720aac67db9686d48ef Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 4 Apr 2018 15:23:32 +1000 Subject: [PATCH 512/828] tests/basics/int_big1.py: Add test for big int in mp_obj_get_int_maybe. --- tests/basics/int_big1.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/basics/int_big1.py b/tests/basics/int_big1.py index 4bf44eb187..996c45b5da 100644 --- a/tests/basics/int_big1.py +++ b/tests/basics/int_big1.py @@ -99,3 +99,7 @@ x = -4611686018427387904 # big # sys.maxsize is a constant mpz, so test it's compatible with dynamic ones import sys print(sys.maxsize + 1 - 1 == sys.maxsize) + +# test extraction of big int value via mp_obj_get_int_maybe +x = 1 << 70 +print('a' * (x + 4 - x)) From dd48ccb1e36170138338825c7a97df3a78562c7d Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 4 Apr 2018 15:26:18 +1000 Subject: [PATCH 513/828] tests/basics: Add test for subclassing an iterable native type. --- tests/basics/subclass_native_iter.py | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/basics/subclass_native_iter.py diff --git a/tests/basics/subclass_native_iter.py b/tests/basics/subclass_native_iter.py new file mode 100644 index 0000000000..0f6b369ad1 --- /dev/null +++ b/tests/basics/subclass_native_iter.py @@ -0,0 +1,7 @@ +# test subclassing a native type which can be iterated over + +class mymap(map): + pass + +m = mymap(lambda x: x + 10, range(4)) +print(list(m)) From 7b7bbd0ee7c17273fdaa3bee1ef25d72e0519a41 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 5 Apr 2018 00:59:49 +1000 Subject: [PATCH 514/828] tests/basics: Add tests for edge cases of nan-box's 47-bit small int. --- tests/basics/builtin_abs_intbig.py | 4 ++++ tests/basics/int_big1.py | 5 +++++ tests/basics/int_big_add.py | 5 +++++ 3 files changed, 14 insertions(+) diff --git a/tests/basics/builtin_abs_intbig.py b/tests/basics/builtin_abs_intbig.py index 3dd5ea89fa..8afb7fc691 100644 --- a/tests/basics/builtin_abs_intbig.py +++ b/tests/basics/builtin_abs_intbig.py @@ -7,3 +7,7 @@ print(abs(-123456789012345678901234567890)) # edge cases for 32 and 64 bit archs (small int overflow when negating) print(abs(-0x3fffffff - 1)) print(abs(-0x3fffffffffffffff - 1)) + +# edge case for nan-boxing with 47-bit small int +i = -0x3fffffffffff +print(abs(i - 1)) diff --git a/tests/basics/int_big1.py b/tests/basics/int_big1.py index 996c45b5da..40d16c455b 100644 --- a/tests/basics/int_big1.py +++ b/tests/basics/int_big1.py @@ -90,6 +90,11 @@ x = 1073741823 # small x = -1073741823 # small x = 1073741824 # big x = -1073741824 # big +# for nan-boxing with 47-bit small ints +print(int('0x3fffffffffff', 16)) # small +print(int('-0x3fffffffffff', 16)) # small +print(int('0x400000000000', 16)) # big +print(int('-0x400000000000', 16)) # big # for 64 bit archs x = 4611686018427387903 # small x = -4611686018427387903 # small diff --git a/tests/basics/int_big_add.py b/tests/basics/int_big_add.py index f0c3336d05..b64b76ff0b 100644 --- a/tests/basics/int_big_add.py +++ b/tests/basics/int_big_add.py @@ -5,6 +5,11 @@ i = 0x3fffffff print(i + i) print(-i + -i) +# 47-bit overflow +i = 0x3fffffffffff +print(i + i) +print(-i + -i) + # 63-bit overflow i = 0x3fffffffffffffff print(i + i) From 22161acf470e49aed359187cbe4db7014d698b05 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 5 Apr 2018 01:03:57 +1000 Subject: [PATCH 515/828] tests/basics/class_super.py: Add tests for store/delete of super attr. --- tests/basics/class_super.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/basics/class_super.py b/tests/basics/class_super.py index 1338ef4523..698fe5dff2 100644 --- a/tests/basics/class_super.py +++ b/tests/basics/class_super.py @@ -34,3 +34,14 @@ class B(A): print(super().bar) # accessing attribute after super() return super().foo().count(2) # calling a subsequent method print(B().foo()) + +# store/delete of super attribute not allowed +assert hasattr(super(B, B()), 'foo') +try: + super(B, B()).foo = 1 +except AttributeError: + print('AttributeError') +try: + del super(B, B()).foo +except AttributeError: + print('AttributeError') From 1bfc774a086127cce539d50c1c1baedd5f609d41 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 5 Apr 2018 01:04:38 +1000 Subject: [PATCH 516/828] tests/basics/string_compare.py: Add test with string that hashes to 0. The string "Q+?" is special in that it hashes to zero with the djb2 algorithm (among other strings), and a zero hash should be incremented to a hash of 1. --- tests/basics/string_compare.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/basics/string_compare.py b/tests/basics/string_compare.py index f011ed3630..6515809b36 100644 --- a/tests/basics/string_compare.py +++ b/tests/basics/string_compare.py @@ -53,3 +53,6 @@ print("1/" <= "1") # that does have a hash, but the lengths of the two strings are different import sys print(sys.version == 'a long string that has a hash') + +# this special string would have a hash of 0 but is incremented to 1 +print('Q+?' == 'Q' + '+?') From 5995a199a327b81553189d53035c586d7b0249dc Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 5 Apr 2018 01:06:40 +1000 Subject: [PATCH 517/828] tests/micropython: Add set of tests for extreme cases of raising exc's. --- tests/micropython/extreme_exc.py | 75 ++++++++++++++++++++++++++++ tests/micropython/extreme_exc.py.exp | 5 ++ 2 files changed, 80 insertions(+) create mode 100644 tests/micropython/extreme_exc.py create mode 100644 tests/micropython/extreme_exc.py.exp diff --git a/tests/micropython/extreme_exc.py b/tests/micropython/extreme_exc.py new file mode 100644 index 0000000000..c180f7cc12 --- /dev/null +++ b/tests/micropython/extreme_exc.py @@ -0,0 +1,75 @@ +# test some extreme cases of allocating exceptions and tracebacks + +import micropython + +# some ports need to allocate heap for the emergency exception +try: + micropython.alloc_emergency_exception_buf(256) +except AttributeError: + pass + +def main(): + # create an exception with many args while heap is locked + # should revert to empty tuple for args + micropython.heap_lock() + e = Exception(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + micropython.heap_unlock() + print(repr(e)) + + # create an exception with a long formatted error message while heap is locked + # should use emergency exception buffer and truncate the message + def f(): + pass + micropython.heap_lock() + try: + f(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=1) + except Exception as er: + e = er + micropython.heap_unlock() + print(repr(e)[:50]) + + # create an exception with a long formatted error message while heap is low + # should use the heap and truncate the message + lst = [] + while 1: + try: + lst = [lst] + except MemoryError: + break + try: + f(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=1) + except Exception as er: + e = er + lst = None + print(repr(e)) + + # raise a deep exception with the heap locked + # should use emergency exception and be unable to resize traceback array + def g(): + g() + micropython.heap_lock() + try: + g() + except Exception as er: + e = er + micropython.heap_unlock() + print(repr(e)) + + # create an exception on the heap with some traceback on the heap, but then + # raise it with the heap locked so it can't allocate any more traceback + exc = Exception('my exception') + try: + raise exc + except: + pass + def h(e): + raise e + micropython.heap_lock() + try: + h(exc) + except Exception as er: + e = er + micropython.heap_unlock() + print(repr(e)) + +main() diff --git a/tests/micropython/extreme_exc.py.exp b/tests/micropython/extreme_exc.py.exp new file mode 100644 index 0000000000..d7d65e03f5 --- /dev/null +++ b/tests/micropython/extreme_exc.py.exp @@ -0,0 +1,5 @@ +Exception() +TypeError("unexpected keyword argument 'abcdefghij +TypeError("unexpected keyword argument 'abc",) +RuntimeError('maximum recursion depth exceeded',) +Exception('my exception',) From f1df86a0177c77769d73bc477570580b4f705acf Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 5 Apr 2018 01:11:26 +1000 Subject: [PATCH 518/828] py/objint: Simplify LHS arg type checking in int binary op functions. The LHS passed to mp_obj_int_binary_op() will always be an integer, either a small int or a big int, so the test for this type doesn't need to include an "other, unsupported type" case. --- py/objint_longlong.c | 5 ++--- py/objint_mpz.c | 6 ++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/py/objint_longlong.c b/py/objint_longlong.c index 3e5ebadaf3..cb8d1672d9 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -124,10 +124,9 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i if (MP_OBJ_IS_SMALL_INT(lhs_in)) { lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs_in); - } else if (MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)) { - lhs_val = ((mp_obj_int_t*)lhs_in)->val; } else { - return MP_OBJ_NULL; // op not supported + assert(MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)); + lhs_val = ((mp_obj_int_t*)lhs_in)->val; } if (MP_OBJ_IS_SMALL_INT(rhs_in)) { diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 17e3ee6d24..0f05c84f47 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -170,11 +170,9 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i if (MP_OBJ_IS_SMALL_INT(lhs_in)) { mpz_init_fixed_from_int(&z_int, z_int_dig, MPZ_NUM_DIG_FOR_INT, MP_OBJ_SMALL_INT_VALUE(lhs_in)); zlhs = &z_int; - } else if (MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)) { - zlhs = &((mp_obj_int_t*)MP_OBJ_TO_PTR(lhs_in))->mpz; } else { - // unsupported type - return MP_OBJ_NULL; + assert(MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)); + zlhs = &((mp_obj_int_t*)MP_OBJ_TO_PTR(lhs_in))->mpz; } // if rhs is small int, then lhs was not (otherwise mp_binary_op handles it) From 4caadc3c013a24af8eaaad846a8eca931cd5653e Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 5 Apr 2018 02:33:48 +1000 Subject: [PATCH 519/828] tests/micropython/extreme_exc.py: Fix test to run on more ports/configs. --- tests/micropython/extreme_exc.py | 12 +++++++++++- tests/micropython/extreme_exc.py.exp | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/micropython/extreme_exc.py b/tests/micropython/extreme_exc.py index c180f7cc12..86c5fed19a 100644 --- a/tests/micropython/extreme_exc.py +++ b/tests/micropython/extreme_exc.py @@ -2,6 +2,15 @@ import micropython +# Check for stackless build, which can't call functions without +# allocating a frame on the heap. +try: + def stackless(): pass + micropython.heap_lock(); stackless(); micropython.heap_unlock() +except RuntimeError: + print("SKIP") + raise SystemExit + # some ports need to allocate heap for the emergency exception try: micropython.alloc_emergency_exception_buf(256) @@ -40,8 +49,9 @@ def main(): f(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=1) except Exception as er: e = er + lst[0] = None lst = None - print(repr(e)) + print(repr(e)[:43]) # raise a deep exception with the heap locked # should use emergency exception and be unable to resize traceback array diff --git a/tests/micropython/extreme_exc.py.exp b/tests/micropython/extreme_exc.py.exp index d7d65e03f5..33f942cbc6 100644 --- a/tests/micropython/extreme_exc.py.exp +++ b/tests/micropython/extreme_exc.py.exp @@ -1,5 +1,5 @@ Exception() TypeError("unexpected keyword argument 'abcdefghij -TypeError("unexpected keyword argument 'abc",) +TypeError("unexpected keyword argument 'abc RuntimeError('maximum recursion depth exceeded',) Exception('my exception',) From b9c78425a66234c45ac5c0b159773363d185d914 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 5 Apr 2018 03:03:16 +1000 Subject: [PATCH 520/828] tests/micropython/extreme_exc.py: Allow to run without any emg exc buf. --- tests/micropython/extreme_exc.py | 6 +++--- tests/micropython/extreme_exc.py.exp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/micropython/extreme_exc.py b/tests/micropython/extreme_exc.py index 86c5fed19a..b9db964068 100644 --- a/tests/micropython/extreme_exc.py +++ b/tests/micropython/extreme_exc.py @@ -35,7 +35,7 @@ def main(): except Exception as er: e = er micropython.heap_unlock() - print(repr(e)[:50]) + print(repr(e)[:10]) # create an exception with a long formatted error message while heap is low # should use the heap and truncate the message @@ -51,7 +51,7 @@ def main(): e = er lst[0] = None lst = None - print(repr(e)[:43]) + print(repr(e)[:10]) # raise a deep exception with the heap locked # should use emergency exception and be unable to resize traceback array @@ -63,7 +63,7 @@ def main(): except Exception as er: e = er micropython.heap_unlock() - print(repr(e)) + print(repr(e)[:13]) # create an exception on the heap with some traceback on the heap, but then # raise it with the heap locked so it can't allocate any more traceback diff --git a/tests/micropython/extreme_exc.py.exp b/tests/micropython/extreme_exc.py.exp index 33f942cbc6..956257e4cd 100644 --- a/tests/micropython/extreme_exc.py.exp +++ b/tests/micropython/extreme_exc.py.exp @@ -1,5 +1,5 @@ Exception() -TypeError("unexpected keyword argument 'abcdefghij -TypeError("unexpected keyword argument 'abc -RuntimeError('maximum recursion depth exceeded',) +TypeError( +TypeError( +RuntimeError( Exception('my exception',) From d6cf5c674952d5ae3463d9b580dac6559576deac Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 31 Mar 2018 21:27:56 -0500 Subject: [PATCH 521/828] py/objstr: In find/rfind, don't crash when end < start. --- py/objstr.c | 5 +++++ tests/basics/string_find.py | 1 + tests/basics/string_rfind.py | 1 + 3 files changed, 7 insertions(+) diff --git a/py/objstr.c b/py/objstr.c index 0b11533f82..da925234e2 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -699,8 +699,13 @@ STATIC mp_obj_t str_finder(size_t n_args, const mp_obj_t *args, int direction, b end = str_index_to_ptr(self_type, haystack, haystack_len, args[3], true); } + if (end < start) { + goto out_error; + } + const byte *p = find_subbytes(start, end - start, needle, needle_len, direction); if (p == NULL) { + out_error: // not found if (is_index) { mp_raise_ValueError("substring not found"); diff --git a/tests/basics/string_find.py b/tests/basics/string_find.py index 4a206eb0e0..f9fcad3e57 100644 --- a/tests/basics/string_find.py +++ b/tests/basics/string_find.py @@ -21,6 +21,7 @@ print("0000".find('-1', 3)) print("0000".find('1', 3)) print("0000".find('1', 4)) print("0000".find('1', 5)) +print("aaaaaaaaaaa".find("bbb", 9, 2)) try: 'abc'.find(1) diff --git a/tests/basics/string_rfind.py b/tests/basics/string_rfind.py index 4d0e84018f..54269d6f59 100644 --- a/tests/basics/string_rfind.py +++ b/tests/basics/string_rfind.py @@ -21,3 +21,4 @@ print("0000".rfind('-1', 3)) print("0000".rfind('1', 3)) print("0000".rfind('1', 4)) print("0000".rfind('1', 5)) +print("aaaaaaaaaaa".rfind("bbb", 9, 2)) From 8f11d0b532bd0203c875ad9e3e4efd8a7014ca15 Mon Sep 17 00:00:00 2001 From: T S Date: Tue, 20 Mar 2018 19:57:33 +0100 Subject: [PATCH 522/828] docs/library/pyb.ADC.rst: Document new features for ADCAll. --- docs/library/pyb.ADC.rst | 66 +++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/docs/library/pyb.ADC.rst b/docs/library/pyb.ADC.rst index 51021fdc1a..58aae6129a 100644 --- a/docs/library/pyb.ADC.rst +++ b/docs/library/pyb.ADC.rst @@ -10,14 +10,16 @@ class ADC -- analog to digital conversion import pyb - adc = pyb.ADC(pin) # create an analog object from a pin - val = adc.read() # read an analog value + adc = pyb.ADC(pin) # create an analog object from a pin + val = adc.read() # read an analog value - adc = pyb.ADCAll(resolution) # create an ADCAll object - val = adc.read_channel(channel) # read the given channel - val = adc.read_core_temp() # read MCU temperature - val = adc.read_core_vbat() # read MCU VBAT - val = adc.read_core_vref() # read MCU VREF + adc = pyb.ADCAll(resolution) # create an ADCAll object + adc = pyb.ADCAll(resolution, mask) # create an ADCAll object for selected analog channels + val = adc.read_channel(channel) # read the given channel + val = adc.read_core_temp() # read MCU temperature + val = adc.read_core_vbat() # read MCU VBAT + val = adc.read_core_vref() # read MCU VREF + val = adc.read_vref() # read MCU supply voltage Constructors @@ -81,27 +83,42 @@ The ADCAll Object .. only:: port_pyboard - Instantiating this changes all ADC pins to analog inputs. The raw MCU temperature, + Instantiating this changes all masked ADC pins to analog inputs. The preprocessed MCU temperature, VREF and VBAT data can be accessed on ADC channels 16, 17 and 18 respectively. - Appropriate scaling will need to be applied. The temperature sensor on the chip - has poor absolute accuracy and is suitable only for detecting temperature changes. + Appropriate scaling is handled according to reference voltage used (usually 3.3V). + The temperature sensor on the chip is factory calibrated and allows to read the die temperature + to +/- 1 degree centigrade. Although this sounds pretty accurate, don't forget that the MCU's internal + temperature is measured. Depending on processing loads and I/O subsystems active the die temperature + may easily be tens of degrees above ambient temperature. On the other hand a pyboard woken up after a + long standby period will show correct ambient temperature within limits mentioned above. - The ``ADCAll`` ``read_core_vbat()`` and ``read_core_vref()`` methods read - the backup battery voltage and the (1.21V nominal) reference voltage using the - 3.3V supply as a reference. Assuming the ``ADCAll`` object has been Instantiated with - ``adc = pyb.ADCAll(12)`` the 3.3V supply voltage may be calculated: - - ``v33 = 3.3 * 1.21 / adc.read_core_vref()`` + The ``ADCAll`` ``read_core_vbat()``, ``read_vref()`` and ``read_core_vref()`` methods read + the backup battery voltage, reference voltage and the (1.21V nominal) reference voltage using the + actual supply as a reference. All results are floating point numbers giving direct voltage values. - If the 3.3V supply is correct the value of ``adc.read_core_vbat()`` will be - valid. If the supply voltage can drop below 3.3V, for example in in battery - powered systems with a discharging battery, the regulator will fail to preserve - the 3.3V supply resulting in an incorrect reading. To produce a value which will - remain valid under these circumstances use the following: + ``read_core_vbat()`` returns the voltage of the backup battery. This voltage is also adjusted according + to the actual supply voltage. To avoid analog input overload the battery voltage is measured + via a voltage divider and scaled according to the divider value. To prevent excessive loads + to the backup battery, the voltage divider is only active during ADC conversion. - ``vback = adc.read_core_vbat() * 1.21 / adc.read_core_vref()`` + ``read_vref()`` is evaluated by measuring the internal voltage reference and backscale it using + factory calibration value of the internal voltage reference. In most cases the reading would be close + to 3.3V. If the pyboard is operated from a battery, the supply voltage may drop to values below 3.3V. + The pyboard will still operate fine as long as the operating conditions are met. With proper settings + of MCU clock, flash access speed and programming mode it is possible to run the pyboard down to + 2 V and still get useful ADC conversion. - It is possible to access these values without incurring the side effects of ``ADCAll``:: + It is very important to make sure analog input voltages never exceed actual supply voltage. + + Other analog input channels (0..15) will return unscaled integer values according to the selected + precision. + + To avoid unwanted activation of analog inputs (channel 0..15) a second prarmeter can be specified. + This parameter is a binary pattern where each requested analog input has the corresponding bit set. + The default value is 0xffffffff which means all analog inputs are active. If just the internal + channels (16..18) are required, the mask value should be 0x70000. + + It is possible to access channle 16..18 values without incurring the side effects of ``ADCAll``:: def adcread(chan): # 16 temp 17 vbat 18 vref assert chan >= 16 and chan <= 18, 'Invalid ADC channel' @@ -140,4 +157,5 @@ The ADCAll Object def temperature(): return 25 + 400 * (3.3 * adcread(16) / 4096 - 0.76) - \ No newline at end of file + Note that this example is only valid for the F405 MCU and all values are not corrected by Vref and + factory calibration data. From cf31d384f1d2ca09f817f154892eaa6860c10144 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 7 Mar 2018 17:48:53 +1100 Subject: [PATCH 523/828] py/stream: Switch stream close operation from method to ioctl. This patch moves the implementation of stream closure from a dedicated method to the ioctl of the stream protocol, for each type that implements closing. The benefits of this are: 1. Rounds out the stream ioctl function, which already includes flush, seek and poll (among other things). 2. Makes calling mp_stream_close() on an object slightly more efficient because it now no longer needs to lookup the close method and call it, rather it just delegates straight to the ioctl function (if it exists). 3. Reduces code size and allows future types that implement the stream protocol to be smaller because they don't need a dedicated close method. Code size reduction is around 200 bytes smaller for x86 archs and around 30 bytes smaller for the bare-metal archs. --- extmod/modlwip.c | 72 ++++++++++++++++------------------ extmod/modussl_axtls.c | 35 ++++++++++------- extmod/modussl_mbedtls.c | 35 ++++++++++------- extmod/modwebrepl.c | 21 +++++++--- extmod/modwebsocket.c | 15 +++---- extmod/vfs_fat_file.c | 30 +++++++------- ports/cc3200/mods/modusocket.c | 15 +++---- ports/esp32/modsocket.c | 27 ++++++------- ports/stm32/modusocket.c | 22 +++++------ ports/unix/file.c | 20 ++++------ ports/unix/modusocket.c | 34 ++++++++++------ ports/zephyr/modusocket.c | 33 ++++++++++------ py/objstringio.c | 30 ++++++-------- py/stream.c | 18 +++++---- py/stream.h | 3 +- 15 files changed, 215 insertions(+), 195 deletions(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 2c194e1bd8..9810089da3 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -637,42 +637,6 @@ STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, size_t n_args, s return socket; } -STATIC mp_obj_t lwip_socket_close(mp_obj_t self_in) { - lwip_socket_obj_t *socket = self_in; - bool socket_is_listener = false; - - if (socket->pcb.tcp == NULL) { - return mp_const_none; - } - switch (socket->type) { - case MOD_NETWORK_SOCK_STREAM: { - if (socket->pcb.tcp->state == LISTEN) { - socket_is_listener = true; - } - if (tcp_close(socket->pcb.tcp) != ERR_OK) { - DEBUG_printf("lwip_close: had to call tcp_abort()\n"); - tcp_abort(socket->pcb.tcp); - } - break; - } - case MOD_NETWORK_SOCK_DGRAM: udp_remove(socket->pcb.udp); break; - //case MOD_NETWORK_SOCK_RAW: raw_remove(socket->pcb.raw); break; - } - socket->pcb.tcp = NULL; - socket->state = _ERR_BADF; - if (socket->incoming.pbuf != NULL) { - if (!socket_is_listener) { - pbuf_free(socket->incoming.pbuf); - } else { - tcp_abort(socket->incoming.connection); - } - socket->incoming.pbuf = NULL; - } - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(lwip_socket_close_obj, lwip_socket_close); - STATIC mp_obj_t lwip_socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { lwip_socket_obj_t *socket = self_in; @@ -1179,6 +1143,38 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ ret |= flags & (MP_STREAM_POLL_RD | MP_STREAM_POLL_WR); } + } else if (request == MP_STREAM_CLOSE) { + bool socket_is_listener = false; + + if (socket->pcb.tcp == NULL) { + return 0; + } + switch (socket->type) { + case MOD_NETWORK_SOCK_STREAM: { + if (socket->pcb.tcp->state == LISTEN) { + socket_is_listener = true; + } + if (tcp_close(socket->pcb.tcp) != ERR_OK) { + DEBUG_printf("lwip_close: had to call tcp_abort()\n"); + tcp_abort(socket->pcb.tcp); + } + break; + } + case MOD_NETWORK_SOCK_DGRAM: udp_remove(socket->pcb.udp); break; + //case MOD_NETWORK_SOCK_RAW: raw_remove(socket->pcb.raw); break; + } + socket->pcb.tcp = NULL; + socket->state = _ERR_BADF; + if (socket->incoming.pbuf != NULL) { + if (!socket_is_listener) { + pbuf_free(socket->incoming.pbuf); + } else { + tcp_abort(socket->incoming.connection); + } + socket->incoming.pbuf = NULL; + } + ret = 0; + } else { *errcode = MP_EINVAL; ret = MP_STREAM_ERROR; @@ -1188,8 +1184,8 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ } STATIC const mp_rom_map_elem_t lwip_socket_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&lwip_socket_close_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&lwip_socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&lwip_socket_bind_obj) }, { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&lwip_socket_listen_obj) }, { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&lwip_socket_accept_obj) }, diff --git a/extmod/modussl_axtls.c b/extmod/modussl_axtls.c index 35e3106cdb..689d33305a 100644 --- a/extmod/modussl_axtls.c +++ b/extmod/modussl_axtls.c @@ -175,6 +175,25 @@ STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in return r; } +STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in); + (void)arg; + switch (request) { + case MP_STREAM_CLOSE: + if (self->ssl_sock != NULL) { + ssl_free(self->ssl_sock); + ssl_ctx_free(self->ssl_ctx); + self->ssl_sock = NULL; + mp_stream_close(self->sock); + } + return 0; + + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } +} + STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { // Currently supports only blocking mode (void)self_in; @@ -185,26 +204,13 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); -STATIC mp_obj_t socket_close(mp_obj_t self_in) { - mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in); - if (self->ssl_sock != NULL) { - ssl_free(self->ssl_sock); - ssl_ctx_free(self->ssl_ctx); - self->ssl_sock = NULL; - return mp_stream_close(self->sock); - } - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); - STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, #if MICROPY_PY_USSL_FINALISER { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) }, #endif @@ -215,6 +221,7 @@ STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_tab STATIC const mp_stream_p_t ussl_socket_stream_p = { .read = socket_read, .write = socket_write, + .ioctl = socket_ioctl, }; STATIC const mp_obj_type_t ussl_socket_type = { diff --git a/extmod/modussl_mbedtls.c b/extmod/modussl_mbedtls.c index 197a0651c6..bd4b0c7253 100644 --- a/extmod/modussl_mbedtls.c +++ b/extmod/modussl_mbedtls.c @@ -274,20 +274,26 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); -STATIC mp_obj_t socket_close(mp_obj_t self_in) { - mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in); +STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in); + (void)arg; + switch (request) { + case MP_STREAM_CLOSE: + mbedtls_pk_free(&self->pkey); + mbedtls_x509_crt_free(&self->cert); + mbedtls_x509_crt_free(&self->cacert); + mbedtls_ssl_free(&self->ssl); + mbedtls_ssl_config_free(&self->conf); + mbedtls_ctr_drbg_free(&self->ctr_drbg); + mbedtls_entropy_free(&self->entropy); + mp_stream_close(self->sock); + return 0; - mbedtls_pk_free(&self->pkey); - mbedtls_x509_crt_free(&self->cert); - mbedtls_x509_crt_free(&self->cacert); - mbedtls_ssl_free(&self->ssl); - mbedtls_ssl_config_free(&self->conf); - mbedtls_ctr_drbg_free(&self->ctr_drbg); - mbedtls_entropy_free(&self->entropy); - - return mp_stream_close(self->sock); + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, @@ -295,9 +301,9 @@ STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, #if MICROPY_PY_USSL_FINALISER - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_getpeercert), MP_ROM_PTR(&mod_ssl_getpeercert_obj) }, }; @@ -307,6 +313,7 @@ STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_tab STATIC const mp_stream_p_t ussl_socket_stream_p = { .read = socket_read, .write = socket_write, + .ioctl = socket_ioctl, }; STATIC const mp_obj_type_t ussl_socket_type = { diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c index 42b30f5ea4..983b5a10ce 100644 --- a/extmod/modwebrepl.c +++ b/extmod/modwebrepl.c @@ -297,12 +297,20 @@ STATIC mp_uint_t webrepl_write(mp_obj_t self_in, const void *buf, mp_uint_t size return stream_p->write(self->sock, buf, size, errcode); } -STATIC mp_obj_t webrepl_close(mp_obj_t self_in) { - mp_obj_webrepl_t *self = MP_OBJ_TO_PTR(self_in); - // TODO: This is a place to do cleanup - return mp_stream_close(self->sock); +STATIC mp_uint_t webrepl_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_webrepl_t *self = MP_OBJ_TO_PTR(o_in); + (void)arg; + switch (request) { + case MP_STREAM_CLOSE: + // TODO: This is a place to do cleanup + mp_stream_close(self->sock); + return 0; + + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(webrepl_close_obj, webrepl_close); STATIC mp_obj_t webrepl_set_password(mp_obj_t passwd_in) { size_t len; @@ -319,13 +327,14 @@ STATIC const mp_rom_map_elem_t webrepl_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&webrepl_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, }; STATIC MP_DEFINE_CONST_DICT(webrepl_locals_dict, webrepl_locals_dict_table); STATIC const mp_stream_p_t webrepl_stream_p = { .read = webrepl_read, .write = webrepl_write, + .ioctl = webrepl_ioctl, }; STATIC const mp_obj_type_t webrepl_type = { diff --git a/extmod/modwebsocket.c b/extmod/modwebsocket.c index a651164b2f..5a826ec64c 100644 --- a/extmod/modwebsocket.c +++ b/extmod/modwebsocket.c @@ -256,6 +256,11 @@ STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t si STATIC mp_uint_t websocket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in); switch (request) { + case MP_STREAM_CLOSE: + // TODO: Send close signaling to the other side, otherwise it's + // abrupt close (connection abort). + mp_stream_close(self->sock); + return 0; case MP_STREAM_GET_DATA_OPTS: return self->ws_flags & FRAME_OPCODE_MASK; case MP_STREAM_SET_DATA_OPTS: { @@ -269,21 +274,13 @@ STATIC mp_uint_t websocket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t } } -STATIC mp_obj_t websocket_close(mp_obj_t self_in) { - mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in); - // TODO: Send close signaling to the other side, otherwise it's - // abrupt close (connection abort). - return mp_stream_close(self->sock); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(websocket_close_obj, websocket_close); - STATIC const mp_rom_map_elem_t websocket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&mp_stream_ioctl_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&websocket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, }; STATIC MP_DEFINE_CONST_DICT(websocket_locals_dict, websocket_locals_dict_table); diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c index 23e5aa10ff..cbd013f160 100644 --- a/extmod/vfs_fat_file.c +++ b/extmod/vfs_fat_file.c @@ -103,22 +103,9 @@ STATIC mp_uint_t file_obj_write(mp_obj_t self_in, const void *buf, mp_uint_t siz } -STATIC mp_obj_t file_obj_close(mp_obj_t self_in) { - pyb_file_obj_t *self = MP_OBJ_TO_PTR(self_in); - // if fs==NULL then the file is closed and in that case this method is a no-op - if (self->fp.obj.fs != NULL) { - FRESULT res = f_close(&self->fp); - if (res != FR_OK) { - mp_raise_OSError(fresult_to_errno_table[res]); - } - } - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(file_obj_close_obj, file_obj_close); - STATIC mp_obj_t file_obj___exit__(size_t n_args, const mp_obj_t *args) { (void)n_args; - return file_obj_close(args[0]); + return mp_stream_close(args[0]); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(file_obj___exit___obj, 4, 4, file_obj___exit__); @@ -153,6 +140,17 @@ STATIC mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, } return 0; + } else if (request == MP_STREAM_CLOSE) { + // if fs==NULL then the file is closed and in that case this method is a no-op + if (self->fp.obj.fs != NULL) { + FRESULT res = f_close(&self->fp); + if (res != FR_OK) { + *errcode = fresult_to_errno_table[res]; + return MP_STREAM_ERROR; + } + } + return 0; + } else { *errcode = MP_EINVAL; return MP_STREAM_ERROR; @@ -234,10 +232,10 @@ STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&file_obj_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) }, { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) }, - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&file_obj_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&file_obj___exit___obj) }, }; diff --git a/ports/cc3200/mods/modusocket.c b/ports/cc3200/mods/modusocket.c index f587e765ae..286b1fb02b 100644 --- a/ports/cc3200/mods/modusocket.c +++ b/ports/cc3200/mods/modusocket.c @@ -336,6 +336,9 @@ STATIC int wlan_socket_ioctl (mod_network_socket_obj_t *s, mp_uint_t request, mp if (SL_FD_ISSET(sd, &xfds)) { ret |= MP_STREAM_POLL_HUP; } + } else if (request == MP_STREAM_CLOSE) { + wlan_socket_close(s); + ret = 0; } else { *_errno = MP_EINVAL; ret = MP_STREAM_ERROR; @@ -466,14 +469,6 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t return s; } -// method socket.close() -STATIC mp_obj_t socket_close(mp_obj_t self_in) { - mod_network_socket_obj_t *self = self_in; - wlan_socket_close(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); - // method socket.bind(address) STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { mod_network_socket_obj_t *self = self_in; @@ -704,8 +699,8 @@ STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) { STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 6, socket_makefile); STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) }, { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) }, { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) }, diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 31d153964c..8b3c280635 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -83,19 +83,6 @@ void check_for_exceptions() { } } -STATIC mp_obj_t socket_close(const mp_obj_t arg0) { - socket_obj_t *self = MP_OBJ_TO_PTR(arg0); - if (self->fd >= 0) { - int ret = lwip_close_r(self->fd); - if (ret != 0) { - exception_from_errno(errno); - } - self->fd = -1; - } - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); - static int _socket_getaddrinfo2(const mp_obj_t host, const mp_obj_t portx, struct addrinfo **resp) { const struct addrinfo hints = { .ai_family = AF_INET, @@ -450,6 +437,16 @@ STATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintpt if (FD_ISSET(socket->fd, &wfds)) ret |= MP_STREAM_POLL_WR; if (FD_ISSET(socket->fd, &efds)) ret |= MP_STREAM_POLL_HUP; return ret; + } else if (request == MP_STREAM_CLOSE) { + if (socket->fd >= 0) { + int ret = lwip_close_r(socket->fd); + if (ret != 0) { + *errcode = errno; + return MP_STREAM_ERROR; + } + socket->fd = -1; + } + return 0; } *errcode = MP_EINVAL; @@ -457,8 +454,8 @@ STATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintpt } STATIC const mp_map_elem_t socket_locals_dict_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&socket_close_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&socket_close_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&mp_stream_close_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&mp_stream_close_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_bind), (mp_obj_t)&socket_bind_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_listen), (mp_obj_t)&socket_listen_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_accept), (mp_obj_t)&socket_accept_obj }, diff --git a/ports/stm32/modusocket.c b/ports/stm32/modusocket.c index 71a237b0d9..0c663437e3 100644 --- a/ports/stm32/modusocket.c +++ b/ports/stm32/modusocket.c @@ -30,6 +30,7 @@ #include "py/objtuple.h" #include "py/objlist.h" #include "py/runtime.h" +#include "py/stream.h" #include "py/mperrno.h" #include "lib/netutils/netutils.h" #include "modnetwork.h" @@ -79,16 +80,6 @@ STATIC void socket_select_nic(mod_network_socket_obj_t *self, const byte *ip) { } } } -// method socket.close() -STATIC mp_obj_t socket_close(mp_obj_t self_in) { - mod_network_socket_obj_t *self = self_in; - if (self->nic != MP_OBJ_NULL) { - self->nic_type->close(self); - self->nic = MP_OBJ_NULL; - } - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); // method socket.bind(address) STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { @@ -347,8 +338,8 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t blocking) { STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) }, { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) }, { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) }, @@ -366,6 +357,13 @@ STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table); mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { mod_network_socket_obj_t *self = self_in; + if (request == MP_STREAM_CLOSE) { + if (self->nic != MP_OBJ_NULL) { + self->nic_type->close(self); + self->nic = MP_OBJ_NULL; + } + return 0; + } return self->nic_type->ioctl(self, request, arg, errcode); } diff --git a/ports/unix/file.c b/ports/unix/file.c index 84e9180821..9bb44c6abd 100644 --- a/ports/unix/file.c +++ b/ports/unix/file.c @@ -118,25 +118,21 @@ STATIC mp_uint_t fdfile_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, i return MP_STREAM_ERROR; } return 0; + case MP_STREAM_CLOSE: + close(o->fd); + #ifdef MICROPY_CPYTHON_COMPAT + o->fd = -1; + #endif + return 0; default: *errcode = EINVAL; return MP_STREAM_ERROR; } } -STATIC mp_obj_t fdfile_close(mp_obj_t self_in) { - mp_obj_fdfile_t *self = MP_OBJ_TO_PTR(self_in); - close(self->fd); -#ifdef MICROPY_CPYTHON_COMPAT - self->fd = -1; -#endif - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(fdfile_close_obj, fdfile_close); - STATIC mp_obj_t fdfile___exit__(size_t n_args, const mp_obj_t *args) { (void)n_args; - return fdfile_close(args[0]); + return mp_stream_close(args[0]); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fdfile___exit___obj, 4, 4, fdfile___exit__); @@ -224,7 +220,7 @@ STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) }, { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) }, { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&fdfile_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&fdfile___exit___obj) }, }; diff --git a/ports/unix/modusocket.c b/ports/unix/modusocket.c index cfb6a9f5ec..ba50e6165e 100644 --- a/ports/unix/modusocket.c +++ b/ports/unix/modusocket.c @@ -108,19 +108,26 @@ STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in return r; } -STATIC mp_obj_t socket_close(mp_obj_t self_in) { - mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); - // There's a POSIX drama regarding return value of close in general, - // and EINTR error in particular. See e.g. - // http://lwn.net/Articles/576478/ - // http://austingroupbugs.net/view.php?id=529 - // The rationale MicroPython follows is that close() just releases - // file descriptor. If you're interested to catch I/O errors before - // closing fd, fsync() it. - close(self->fd); - return mp_const_none; +STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_socket_t *self = MP_OBJ_TO_PTR(o_in); + (void)arg; + switch (request) { + case MP_STREAM_CLOSE: + // There's a POSIX drama regarding return value of close in general, + // and EINTR error in particular. See e.g. + // http://lwn.net/Articles/576478/ + // http://austingroupbugs.net/view.php?id=529 + // The rationale MicroPython follows is that close() just releases + // file descriptor. If you're interested to catch I/O errors before + // closing fd, fsync() it. + close(self->fd); + return 0; + + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); STATIC mp_obj_t socket_fileno(mp_obj_t self_in) { mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); @@ -359,7 +366,7 @@ STATIC const mp_rom_map_elem_t usocket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) }, { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) }, { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, }; STATIC MP_DEFINE_CONST_DICT(usocket_locals_dict, usocket_locals_dict_table); @@ -367,6 +374,7 @@ STATIC MP_DEFINE_CONST_DICT(usocket_locals_dict, usocket_locals_dict_table); STATIC const mp_stream_p_t usocket_stream_p = { .read = socket_read, .write = socket_write, + .ioctl = socket_ioctl, }; const mp_obj_type_t mp_type_socket = { diff --git a/ports/zephyr/modusocket.c b/ports/zephyr/modusocket.c index 95414a49b4..84d6fa7297 100644 --- a/ports/zephyr/modusocket.c +++ b/ports/zephyr/modusocket.c @@ -299,20 +299,31 @@ STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 3, socket_makefile); -STATIC mp_obj_t socket_close(mp_obj_t self_in) { - socket_obj_t *socket = self_in; - if (socket->ctx != -1) { - int res = zsock_close(socket->ctx); - RAISE_SOCK_ERRNO(res); - socket->ctx = -1; +STATIC mp_uint_t sock_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + socket_obj_t *socket = o_in; + (void)arg; + switch (request) { + case MP_STREAM_CLOSE: + if (socket->ctx != -1) { + int res = zsock_close(socket->ctx); + RAISE_SOCK_ERRNO(res); + if (res == -1) { + *errcode = errno; + return MP_STREAM_ERROR; + } + socket->ctx = -1; + } + return 0; + + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; } - return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) }, { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) }, { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) }, @@ -332,7 +343,7 @@ STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table); STATIC const mp_stream_p_t socket_stream_p = { .read = sock_read, .write = sock_write, - //.ioctl = sock_ioctl, + .ioctl = sock_ioctl, }; STATIC const mp_obj_type_t socket_type = { diff --git a/py/objstringio.c b/py/objstringio.c index 5c50aa3174..b405ee21e3 100644 --- a/py/objstringio.c +++ b/py/objstringio.c @@ -143,6 +143,17 @@ STATIC mp_uint_t stringio_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, } case MP_STREAM_FLUSH: return 0; + case MP_STREAM_CLOSE: + #if MICROPY_CPYTHON_COMPAT + vstr_free(o->vstr); + o->vstr = NULL; + #else + vstr_clear(o->vstr); + o->vstr->alloc = 0; + o->vstr->len = 0; + o->pos = 0; + #endif + return 0; default: *errcode = MP_EINVAL; return MP_STREAM_ERROR; @@ -159,24 +170,9 @@ STATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_getvalue_obj, stringio_getvalue); -STATIC mp_obj_t stringio_close(mp_obj_t self_in) { - mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in); -#if MICROPY_CPYTHON_COMPAT - vstr_free(self->vstr); - self->vstr = NULL; -#else - vstr_clear(self->vstr); - self->vstr->alloc = 0; - self->vstr->len = 0; - self->pos = 0; -#endif - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_close_obj, stringio_close); - STATIC mp_obj_t stringio___exit__(size_t n_args, const mp_obj_t *args) { (void)n_args; - return stringio_close(args[0]); + return mp_stream_close(args[0]); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stringio___exit___obj, 4, 4, stringio___exit__); @@ -233,7 +229,7 @@ STATIC const mp_rom_map_elem_t stringio_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) }, { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&stringio_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR_getvalue), MP_ROM_PTR(&stringio_getvalue_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&stringio___exit___obj) }, diff --git a/py/stream.c b/py/stream.c index 453dee769f..f51f634b6f 100644 --- a/py/stream.c +++ b/py/stream.c @@ -105,13 +105,6 @@ const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) { return stream_p; } -mp_obj_t mp_stream_close(mp_obj_t stream) { - // TODO: Still consider using ioctl for close - mp_obj_t dest[2]; - mp_load_method(stream, MP_QSTR_close, dest); - return mp_call_method_n_kw(0, 0, dest); -} - STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte flags) { const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_READ); @@ -434,6 +427,17 @@ mp_obj_t mp_stream_unbuffered_iter(mp_obj_t self) { return MP_OBJ_STOP_ITERATION; } +mp_obj_t mp_stream_close(mp_obj_t stream) { + const mp_stream_p_t *stream_p = mp_get_stream_raise(stream, MP_STREAM_OP_IOCTL); + int error; + mp_uint_t res = stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, &error); + if (res == MP_STREAM_ERROR) { + mp_raise_OSError(error); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_close_obj, mp_stream_close); + STATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args) { const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_IOCTL); diff --git a/py/stream.h b/py/stream.h index fbe3d7d859..a7d8d08f14 100644 --- a/py/stream.h +++ b/py/stream.h @@ -35,7 +35,7 @@ #define MP_STREAM_FLUSH (1) #define MP_STREAM_SEEK (2) #define MP_STREAM_POLL (3) -//#define MP_STREAM_CLOSE (4) // Not yet implemented +#define MP_STREAM_CLOSE (4) #define MP_STREAM_TIMEOUT (5) // Get/set timeout (single op) #define MP_STREAM_GET_OPTS (6) // Get stream options #define MP_STREAM_SET_OPTS (7) // Set stream options @@ -69,6 +69,7 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_unbuffered_readline_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_unbuffered_readlines_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write_obj); MP_DECLARE_CONST_FUN_OBJ_2(mp_stream_write1_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_close_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_seek_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_tell_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_flush_obj); From 6a693db71d032518dedc50731376c15bebe6cec9 Mon Sep 17 00:00:00 2001 From: armink Date: Wed, 21 Mar 2018 10:21:29 +0800 Subject: [PATCH 524/828] extmod/re1.5: Fix compilecode.c compile problem on IAR tool chain. The 2nd and 3rd args of the ternary operator are treated like they are in the same expression and must have similar types. void is not compatible with int so that's why the compiler is complaining. --- extmod/re1.5/compilecode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extmod/re1.5/compilecode.c b/extmod/re1.5/compilecode.c index 3267a4190d..a685a508a0 100644 --- a/extmod/re1.5/compilecode.c +++ b/extmod/re1.5/compilecode.c @@ -5,9 +5,9 @@ #include "re1.5.h" #define INSERT_CODE(at, num, pc) \ - ((code ? memmove(code + at + num, code + at, pc - at) : (void)0), pc += num) + ((code ? memmove(code + at + num, code + at, pc - at) : 0), pc += num) #define REL(at, to) (to - at - 2) -#define EMIT(at, byte) (code ? (code[at] = byte) : (void)(at)) +#define EMIT(at, byte) (code ? (code[at] = byte) : (at)) #define PC (prog->bytelen) static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) From cbf981f3307661c205d27f3a418be3989ab47c5e Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 1 Apr 2018 12:15:35 -0500 Subject: [PATCH 525/828] py/objgenerator: Check stack before resuming a generator. This turns a hard crash in a recursive generator into a 'maximum recursion depth exceeded' exception. --- py/objgenerator.c | 2 ++ tests/run-tests | 1 + tests/stress/recursive_gen.py | 9 +++++++++ 3 files changed, 12 insertions(+) create mode 100644 tests/stress/recursive_gen.py diff --git a/py/objgenerator.c b/py/objgenerator.c index 8c1260b60f..5fd13f831d 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -32,6 +32,7 @@ #include "py/bc.h" #include "py/objgenerator.h" #include "py/objfun.h" +#include "py/stackctrl.h" /******************************************************************************/ /* generator wrapper */ @@ -92,6 +93,7 @@ STATIC void gen_instance_print(const mp_print_t *print, mp_obj_t self_in, mp_pri } mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) { + MP_STACK_CHECK(); mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_gen_instance)); mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in); if (self->code_state.ip == 0) { diff --git a/tests/run-tests b/tests/run-tests index ef2f4bc6a5..42037831d7 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -367,6 +367,7 @@ def run_tests(pyb, tests, args, base_path="."): skip_tests.add('micropython/heapalloc_iter.py') # requires generators skip_tests.add('micropython/schedule.py') # native code doesn't check pending events skip_tests.add('stress/gc_trace.py') # requires yield + skip_tests.add('stress/recursive_gen.py') # requires yield for test_file in tests: test_file = test_file.replace('\\', '/') diff --git a/tests/stress/recursive_gen.py b/tests/stress/recursive_gen.py new file mode 100644 index 0000000000..65f5d8d470 --- /dev/null +++ b/tests/stress/recursive_gen.py @@ -0,0 +1,9 @@ +# test deeply recursive generators + +def gen(): + yield from gen() + +try: + list(gen()) +except RuntimeError: + print('RuntimeError') From 90bb98e83daf714f22eb3f8af6ae57ec4078ee32 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 6 Apr 2018 01:04:08 +0200 Subject: [PATCH 526/828] stm32/dac: Add support for H7 MCUs. Includes a fix for H7 DAC DMA requests. --- ports/stm32/dac.c | 10 ++++++++++ ports/stm32/dma.c | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c index 9d8d7a872f..bce30dbc7e 100644 --- a/ports/stm32/dac.c +++ b/ports/stm32/dac.c @@ -65,6 +65,10 @@ #if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC +#if defined(STM32H7) +#define DAC DAC1 +#endif + STATIC DAC_HandleTypeDef DAC_Handle; void dac_init(void) { @@ -160,6 +164,8 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp // DAC peripheral clock #if defined(STM32F4) || defined(STM32F7) __DAC_CLK_ENABLE(); + #elif defined(STM32H7) + __HAL_RCC_DAC12_CLK_ENABLE(); #elif defined(STM32L4) __HAL_RCC_DAC1_CLK_ENABLE(); #else @@ -256,10 +262,14 @@ STATIC mp_obj_t pyb_dac_deinit(mp_obj_t self_in) { pyb_dac_obj_t *self = self_in; if (self->dac_channel == DAC_CHANNEL_1) { DAC_Handle.Instance->CR &= ~DAC_CR_EN1; + #ifndef STM32H7 DAC_Handle.Instance->CR |= DAC_CR_BOFF1; + #endif } else { DAC_Handle.Instance->CR &= ~DAC_CR_EN2; + #ifndef STM32H7 DAC_Handle.Instance->CR |= DAC_CR_BOFF2; + #endif } return mp_const_none; } diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index b0efd2a938..7ea2eaa3b4 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -336,8 +336,8 @@ const dma_descr_t dma_SPI_2_TX = { DMA1_Stream4, DMA_REQUEST_SPI2_TX, DMA_MEMORY const dma_descr_t dma_I2C_3_TX = { DMA1_Stream4, DMA_REQUEST_I2C3_TX, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c }; const dma_descr_t dma_I2C_4_TX = { DMA1_Stream5, BDMA_REQUEST_I2C4_TX, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_spi_i2c }; #if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC -const dma_descr_t dma_DAC_1_TX = { DMA1_Stream5, DMA_REQUEST_DAC1_TX, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_dac }; -const dma_descr_t dma_DAC_2_TX = { DMA1_Stream6, DMA_REQUEST_DAC2_TX, DMA_MEMORY_TO_PERIPH, dma_id_6, &dma_init_struct_dac }; +const dma_descr_t dma_DAC_1_TX = { DMA1_Stream5, DMA_REQUEST_DAC1_CH1, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_dac }; +const dma_descr_t dma_DAC_2_TX = { DMA1_Stream6, DMA_REQUEST_DAC1_CH2, DMA_MEMORY_TO_PERIPH, dma_id_6, &dma_init_struct_dac }; #endif const dma_descr_t dma_SPI_3_TX = { DMA1_Stream7, DMA_REQUEST_SPI3_TX, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c }; const dma_descr_t dma_I2C_1_TX = { DMA1_Stream7, DMA_REQUEST_I2C1_TX, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c }; From e1e49adb865d96f94c41c7c9ba7feafe3b77d413 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 6 Apr 2018 01:05:22 +0200 Subject: [PATCH 527/828] stm32/boards/NUCLEO_H743ZI: Enable DAC peripheral. --- ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h | 1 + ports/stm32/boards/NUCLEO_H743ZI/pins.csv | 2 ++ 2 files changed, 3 insertions(+) diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h index 7aea8b06a6..d2a34795e7 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h @@ -3,6 +3,7 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_ADC (0) +#define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_USB (1) #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) diff --git a/ports/stm32/boards/NUCLEO_H743ZI/pins.csv b/ports/stm32/boards/NUCLEO_H743ZI/pins.csv index 92627ba957..30910c4dd5 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/pins.csv +++ b/ports/stm32/boards/NUCLEO_H743ZI/pins.csv @@ -20,6 +20,8 @@ D12,PB14 D13,PI1 D14,PB9 D15,PB8 +DAC1,PA4 +DAC2,PA5 LED1,PB0 LED2,PB7 LED3,PB14 From 69bf23c9cfacae4745c260b9a75ca5144ffb353b Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Apr 2018 14:28:39 +1000 Subject: [PATCH 528/828] stm32/i2c: Update HAL macros to use new __HAL_RCC prefix. --- ports/stm32/i2c.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index d4f6080077..8f94e783df 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -262,28 +262,28 @@ void i2c_init(I2C_HandleTypeDef *i2c) { i2c_unit = 1; scl_pin = MICROPY_HW_I2C1_SCL; sda_pin = MICROPY_HW_I2C1_SDA; - __I2C1_CLK_ENABLE(); + __HAL_RCC_I2C1_CLK_ENABLE(); #endif #if defined(MICROPY_HW_I2C2_SCL) } else if (i2c == &I2CHandle2) { i2c_unit = 2; scl_pin = MICROPY_HW_I2C2_SCL; sda_pin = MICROPY_HW_I2C2_SDA; - __I2C2_CLK_ENABLE(); + __HAL_RCC_I2C2_CLK_ENABLE(); #endif #if defined(MICROPY_HW_I2C3_SCL) } else if (i2c == &I2CHandle3) { i2c_unit = 3; scl_pin = MICROPY_HW_I2C3_SCL; sda_pin = MICROPY_HW_I2C3_SDA; - __I2C3_CLK_ENABLE(); + __HAL_RCC_I2C3_CLK_ENABLE(); #endif #if defined(MICROPY_HW_I2C4_SCL) } else if (i2c == &I2CHandle4) { i2c_unit = 4; scl_pin = MICROPY_HW_I2C4_SCL; sda_pin = MICROPY_HW_I2C4_SDA; - __I2C4_CLK_ENABLE(); + __HAL_RCC_I2C4_CLK_ENABLE(); #endif } else { // I2C does not exist for this board (shouldn't get here, should be checked by caller) @@ -339,25 +339,25 @@ void i2c_deinit(I2C_HandleTypeDef *i2c) { if (0) { #if defined(MICROPY_HW_I2C1_SCL) } else if (i2c->Instance == I2C1) { - __I2C1_FORCE_RESET(); - __I2C1_RELEASE_RESET(); - __I2C1_CLK_DISABLE(); + __HAL_RCC_I2C1_FORCE_RESET(); + __HAL_RCC_I2C1_RELEASE_RESET(); + __HAL_RCC_I2C1_CLK_DISABLE(); HAL_NVIC_DisableIRQ(I2C1_EV_IRQn); HAL_NVIC_DisableIRQ(I2C1_ER_IRQn); #endif #if defined(MICROPY_HW_I2C2_SCL) } else if (i2c->Instance == I2C2) { - __I2C2_FORCE_RESET(); - __I2C2_RELEASE_RESET(); - __I2C2_CLK_DISABLE(); + __HAL_RCC_I2C2_FORCE_RESET(); + __HAL_RCC_I2C2_RELEASE_RESET(); + __HAL_RCC_I2C2_CLK_DISABLE(); HAL_NVIC_DisableIRQ(I2C2_EV_IRQn); HAL_NVIC_DisableIRQ(I2C2_ER_IRQn); #endif #if defined(MICROPY_HW_I2C3_SCL) } else if (i2c->Instance == I2C3) { - __I2C3_FORCE_RESET(); - __I2C3_RELEASE_RESET(); - __I2C3_CLK_DISABLE(); + __HAL_RCC_I2C3_FORCE_RESET(); + __HAL_RCC_I2C3_RELEASE_RESET(); + __HAL_RCC_I2C3_CLK_DISABLE(); HAL_NVIC_DisableIRQ(I2C3_EV_IRQn); HAL_NVIC_DisableIRQ(I2C3_ER_IRQn); #endif From 22f1414abb538e80bda6c9c7123534923558d0fb Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Apr 2018 14:33:18 +1000 Subject: [PATCH 529/828] stm32/i2c: Fully support peripheral I2C4. --- ports/stm32/i2c.c | 4 ++++ ports/stm32/i2c.h | 1 + 2 files changed, 5 insertions(+) diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index 8f94e783df..6c135b3a5a 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -650,6 +650,10 @@ STATIC mp_obj_t pyb_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_ } else if (strcmp(port, MICROPY_HW_I2C3_NAME) == 0) { i2c_id = 3; #endif + #ifdef MICROPY_HW_I2C4_NAME + } else if (strcmp(port, MICROPY_HW_I2C4_NAME) == 0) { + i2c_id = 4; + #endif } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "I2C(%s) doesn't exist", port)); diff --git a/ports/stm32/i2c.h b/ports/stm32/i2c.h index e17621f7c3..6d3ff2201f 100644 --- a/ports/stm32/i2c.h +++ b/ports/stm32/i2c.h @@ -42,6 +42,7 @@ typedef struct _pyb_i2c_obj_t { extern I2C_HandleTypeDef I2CHandle1; extern I2C_HandleTypeDef I2CHandle2; extern I2C_HandleTypeDef I2CHandle3; +extern I2C_HandleTypeDef I2CHandle4; extern const mp_obj_type_t pyb_i2c_type; extern const pyb_i2c_obj_t pyb_i2c_obj[4]; From 605fdcf754c2c3f80f71e2dc83dcb3a4e74e5d95 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Apr 2018 14:39:51 +1000 Subject: [PATCH 530/828] tests/stress/recursive_gen: Add test for recursive gen with iter. --- tests/stress/recursive_gen.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/stress/recursive_gen.py b/tests/stress/recursive_gen.py index 65f5d8d470..0e0d3914ee 100644 --- a/tests/stress/recursive_gen.py +++ b/tests/stress/recursive_gen.py @@ -1,9 +1,18 @@ # test deeply recursive generators +# simple "yield from" recursion def gen(): yield from gen() - try: list(gen()) except RuntimeError: print('RuntimeError') + +# recursion via an iterator over a generator +def gen2(): + for x in gen2(): + yield x +try: + next(gen2()) +except RuntimeError: + print('RuntimeError') From 5ad27d4b8bb248954d98178e068a382599dadfa6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Apr 2018 14:42:42 +1000 Subject: [PATCH 531/828] tests: Move recursive tests to the tests/stress/ subdir. Keeping all the stress related tests in one place makes it easier to stress-test a given port, and to also not run such tests on ports that can't handle them. --- tests/run-tests | 3 --- tests/{misc => stress}/recursion.py | 0 tests/{misc => stress}/recursive_data.py | 0 tests/{misc => stress}/recursive_data.py.exp | 0 tests/{misc => stress}/recursive_iternext.py | 0 tests/{misc => stress}/recursive_iternext.py.exp | 0 6 files changed, 3 deletions(-) rename tests/{misc => stress}/recursion.py (100%) rename tests/{misc => stress}/recursive_data.py (100%) rename tests/{misc => stress}/recursive_data.py.exp (100%) rename tests/{misc => stress}/recursive_iternext.py (100%) rename tests/{misc => stress}/recursive_iternext.py.exp (100%) diff --git a/tests/run-tests b/tests/run-tests index 42037831d7..71eab4905b 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -312,9 +312,6 @@ def run_tests(pyb, tests, args, base_path="."): if args.target == 'wipy': skip_tests.add('misc/print_exception.py') # requires error reporting full - skip_tests.add('misc/recursion.py') # requires stack checking enabled - skip_tests.add('misc/recursive_data.py') # requires stack checking enabled - skip_tests.add('misc/recursive_iternext.py') # requires stack checking enabled skip_tests.update({'extmod/uctypes_%s.py' % t for t in 'bytearray le native_le ptr_le ptr_native_le sizeof sizeof_native array_assign_le array_assign_native_le'.split()}) # requires uctypes skip_tests.add('extmod/zlibd_decompress.py') # requires zlib skip_tests.add('extmod/uheapq1.py') # uheapq not supported by WiPy diff --git a/tests/misc/recursion.py b/tests/stress/recursion.py similarity index 100% rename from tests/misc/recursion.py rename to tests/stress/recursion.py diff --git a/tests/misc/recursive_data.py b/tests/stress/recursive_data.py similarity index 100% rename from tests/misc/recursive_data.py rename to tests/stress/recursive_data.py diff --git a/tests/misc/recursive_data.py.exp b/tests/stress/recursive_data.py.exp similarity index 100% rename from tests/misc/recursive_data.py.exp rename to tests/stress/recursive_data.py.exp diff --git a/tests/misc/recursive_iternext.py b/tests/stress/recursive_iternext.py similarity index 100% rename from tests/misc/recursive_iternext.py rename to tests/stress/recursive_iternext.py diff --git a/tests/misc/recursive_iternext.py.exp b/tests/stress/recursive_iternext.py.exp similarity index 100% rename from tests/misc/recursive_iternext.py.exp rename to tests/stress/recursive_iternext.py.exp From ef12a4bd05cdd531d9c130763ffb2470e9c0fb54 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Apr 2018 15:06:47 +1000 Subject: [PATCH 532/828] py: Refactor how native emitter code is compiled with a file per arch. Instead of emitnative.c having configuration code for each supported architecture, and then compiling this file multiple times with different macros defined, this patch adds a file per architecture with the necessary code to configure the native emitter. These files then #include the emitnative.c file. This simplifies emitnative.c (which is already very large), and simplifies the build system because emitnative.c no longer needs special handling for compilation and qstr extraction. --- py/asmthumb.h | 1 + py/emitnarm.c | 15 ++++++++ py/emitnative.c | 97 +----------------------------------------------- py/emitnthumb.c | 15 ++++++++ py/emitnx64.c | 15 ++++++++ py/emitnx86.c | 67 +++++++++++++++++++++++++++++++++ py/emitnxtensa.c | 15 ++++++++ py/mkrules.mk | 5 +-- py/py.mk | 26 +------------ 9 files changed, 132 insertions(+), 124 deletions(-) create mode 100644 py/emitnarm.c create mode 100644 py/emitnthumb.c create mode 100644 py/emitnx64.c create mode 100644 py/emitnx86.c create mode 100644 py/emitnxtensa.c diff --git a/py/asmthumb.h b/py/asmthumb.h index 552ad75fca..8a7df5d504 100644 --- a/py/asmthumb.h +++ b/py/asmthumb.h @@ -26,6 +26,7 @@ #ifndef MICROPY_INCLUDED_PY_ASMTHUMB_H #define MICROPY_INCLUDED_PY_ASMTHUMB_H +#include #include "py/misc.h" #include "py/asmbase.h" diff --git a/py/emitnarm.c b/py/emitnarm.c new file mode 100644 index 0000000000..1b585f821b --- /dev/null +++ b/py/emitnarm.c @@ -0,0 +1,15 @@ +// ARM specific stuff + +#include "py/mpconfig.h" + +#if MICROPY_EMIT_ARM + +// This is defined so that the assembler exports generic assembler API macros +#define GENERIC_ASM_API (1) +#include "py/asmarm.h" + +#define N_ARM (1) +#define EXPORT_FUN(name) emit_native_arm_##name +#include "py/emitnative.c" + +#endif diff --git a/py/emitnative.c b/py/emitnative.c index 964db95523..7e017ba39f 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -57,14 +57,7 @@ #endif // wrapper around everything in this file -#if (MICROPY_EMIT_X64 && N_X64) \ - || (MICROPY_EMIT_X86 && N_X86) \ - || (MICROPY_EMIT_THUMB && N_THUMB) \ - || (MICROPY_EMIT_ARM && N_ARM) \ - || (MICROPY_EMIT_XTENSA && N_XTENSA) \ - -// this is defined so that the assembler exports generic assembler API macros -#define GENERIC_ASM_API (1) +#if N_X64 || N_X86 || N_THUMB || N_ARM || N_XTENSA // define additional generic helper macros #define ASM_MOV_LOCAL_IMM_VIA(as, local_num, imm, reg_temp) \ @@ -73,94 +66,6 @@ ASM_MOV_LOCAL_REG((as), (local_num), (reg_temp)); \ } while (false) -#if N_X64 - -// x64 specific stuff -#include "py/asmx64.h" -#define EXPORT_FUN(name) emit_native_x64_##name - -#elif N_X86 - -// x86 specific stuff - -STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = { - [MP_F_CONVERT_OBJ_TO_NATIVE] = 2, - [MP_F_CONVERT_NATIVE_TO_OBJ] = 2, - [MP_F_LOAD_NAME] = 1, - [MP_F_LOAD_GLOBAL] = 1, - [MP_F_LOAD_BUILD_CLASS] = 0, - [MP_F_LOAD_ATTR] = 2, - [MP_F_LOAD_METHOD] = 3, - [MP_F_LOAD_SUPER_METHOD] = 2, - [MP_F_STORE_NAME] = 2, - [MP_F_STORE_GLOBAL] = 2, - [MP_F_STORE_ATTR] = 3, - [MP_F_OBJ_SUBSCR] = 3, - [MP_F_OBJ_IS_TRUE] = 1, - [MP_F_UNARY_OP] = 2, - [MP_F_BINARY_OP] = 3, - [MP_F_BUILD_TUPLE] = 2, - [MP_F_BUILD_LIST] = 2, - [MP_F_LIST_APPEND] = 2, - [MP_F_BUILD_MAP] = 1, - [MP_F_STORE_MAP] = 3, -#if MICROPY_PY_BUILTINS_SET - [MP_F_BUILD_SET] = 2, - [MP_F_STORE_SET] = 2, -#endif - [MP_F_MAKE_FUNCTION_FROM_RAW_CODE] = 3, - [MP_F_NATIVE_CALL_FUNCTION_N_KW] = 3, - [MP_F_CALL_METHOD_N_KW] = 3, - [MP_F_CALL_METHOD_N_KW_VAR] = 3, - [MP_F_NATIVE_GETITER] = 2, - [MP_F_NATIVE_ITERNEXT] = 1, - [MP_F_NLR_PUSH] = 1, - [MP_F_NLR_POP] = 0, - [MP_F_NATIVE_RAISE] = 1, - [MP_F_IMPORT_NAME] = 3, - [MP_F_IMPORT_FROM] = 2, - [MP_F_IMPORT_ALL] = 1, -#if MICROPY_PY_BUILTINS_SLICE - [MP_F_NEW_SLICE] = 3, -#endif - [MP_F_UNPACK_SEQUENCE] = 3, - [MP_F_UNPACK_EX] = 3, - [MP_F_DELETE_NAME] = 1, - [MP_F_DELETE_GLOBAL] = 1, - [MP_F_NEW_CELL] = 1, - [MP_F_MAKE_CLOSURE_FROM_RAW_CODE] = 3, - [MP_F_SETUP_CODE_STATE] = 5, - [MP_F_SMALL_INT_FLOOR_DIVIDE] = 2, - [MP_F_SMALL_INT_MODULO] = 2, -}; - -#include "py/asmx86.h" -#define EXPORT_FUN(name) emit_native_x86_##name - -#elif N_THUMB - -// thumb specific stuff -#include "py/asmthumb.h" -#define EXPORT_FUN(name) emit_native_thumb_##name - -#elif N_ARM - -// ARM specific stuff -#include "py/asmarm.h" -#define EXPORT_FUN(name) emit_native_arm_##name - -#elif N_XTENSA - -// Xtensa specific stuff -#include "py/asmxtensa.h" -#define EXPORT_FUN(name) emit_native_xtensa_##name - -#else - -#error unknown native emitter - -#endif - #define EMIT_NATIVE_VIPER_TYPE_ERROR(emit, ...) do { \ *emit->error_slot = mp_obj_new_exception_msg_varg(&mp_type_ViperTypeError, __VA_ARGS__); \ } while (0) diff --git a/py/emitnthumb.c b/py/emitnthumb.c new file mode 100644 index 0000000000..2b68ca3a13 --- /dev/null +++ b/py/emitnthumb.c @@ -0,0 +1,15 @@ +// thumb specific stuff + +#include "py/mpconfig.h" + +#if MICROPY_EMIT_THUMB + +// this is defined so that the assembler exports generic assembler API macros +#define GENERIC_ASM_API (1) +#include "py/asmthumb.h" + +#define N_THUMB (1) +#define EXPORT_FUN(name) emit_native_thumb_##name +#include "py/emitnative.c" + +#endif diff --git a/py/emitnx64.c b/py/emitnx64.c new file mode 100644 index 0000000000..b9800f636e --- /dev/null +++ b/py/emitnx64.c @@ -0,0 +1,15 @@ +// x64 specific stuff + +#include "py/mpconfig.h" + +#if MICROPY_EMIT_X64 + +// This is defined so that the assembler exports generic assembler API macros +#define GENERIC_ASM_API (1) +#include "py/asmx64.h" + +#define N_X64 (1) +#define EXPORT_FUN(name) emit_native_x64_##name +#include "py/emitnative.c" + +#endif diff --git a/py/emitnx86.c b/py/emitnx86.c new file mode 100644 index 0000000000..d4cd24d74f --- /dev/null +++ b/py/emitnx86.c @@ -0,0 +1,67 @@ +// x86 specific stuff + +#include "py/mpconfig.h" + +#if MICROPY_EMIT_X86 + +// This is defined so that the assembler exports generic assembler API macros +#define GENERIC_ASM_API (1) +#include "py/asmx86.h" + +// x86 needs a table to know how many args a given function has +STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = { + [MP_F_CONVERT_OBJ_TO_NATIVE] = 2, + [MP_F_CONVERT_NATIVE_TO_OBJ] = 2, + [MP_F_LOAD_NAME] = 1, + [MP_F_LOAD_GLOBAL] = 1, + [MP_F_LOAD_BUILD_CLASS] = 0, + [MP_F_LOAD_ATTR] = 2, + [MP_F_LOAD_METHOD] = 3, + [MP_F_LOAD_SUPER_METHOD] = 2, + [MP_F_STORE_NAME] = 2, + [MP_F_STORE_GLOBAL] = 2, + [MP_F_STORE_ATTR] = 3, + [MP_F_OBJ_SUBSCR] = 3, + [MP_F_OBJ_IS_TRUE] = 1, + [MP_F_UNARY_OP] = 2, + [MP_F_BINARY_OP] = 3, + [MP_F_BUILD_TUPLE] = 2, + [MP_F_BUILD_LIST] = 2, + [MP_F_LIST_APPEND] = 2, + [MP_F_BUILD_MAP] = 1, + [MP_F_STORE_MAP] = 3, + #if MICROPY_PY_BUILTINS_SET + [MP_F_BUILD_SET] = 2, + [MP_F_STORE_SET] = 2, + #endif + [MP_F_MAKE_FUNCTION_FROM_RAW_CODE] = 3, + [MP_F_NATIVE_CALL_FUNCTION_N_KW] = 3, + [MP_F_CALL_METHOD_N_KW] = 3, + [MP_F_CALL_METHOD_N_KW_VAR] = 3, + [MP_F_NATIVE_GETITER] = 2, + [MP_F_NATIVE_ITERNEXT] = 1, + [MP_F_NLR_PUSH] = 1, + [MP_F_NLR_POP] = 0, + [MP_F_NATIVE_RAISE] = 1, + [MP_F_IMPORT_NAME] = 3, + [MP_F_IMPORT_FROM] = 2, + [MP_F_IMPORT_ALL] = 1, + #if MICROPY_PY_BUILTINS_SLICE + [MP_F_NEW_SLICE] = 3, + #endif + [MP_F_UNPACK_SEQUENCE] = 3, + [MP_F_UNPACK_EX] = 3, + [MP_F_DELETE_NAME] = 1, + [MP_F_DELETE_GLOBAL] = 1, + [MP_F_NEW_CELL] = 1, + [MP_F_MAKE_CLOSURE_FROM_RAW_CODE] = 3, + [MP_F_SETUP_CODE_STATE] = 5, + [MP_F_SMALL_INT_FLOOR_DIVIDE] = 2, + [MP_F_SMALL_INT_MODULO] = 2, +}; + +#define N_X86 (1) +#define EXPORT_FUN(name) emit_native_x86_##name +#include "py/emitnative.c" + +#endif diff --git a/py/emitnxtensa.c b/py/emitnxtensa.c new file mode 100644 index 0000000000..1a423e21eb --- /dev/null +++ b/py/emitnxtensa.c @@ -0,0 +1,15 @@ +// Xtensa specific stuff + +#include "py/mpconfig.h" + +#if MICROPY_EMIT_XTENSA + +// this is defined so that the assembler exports generic assembler API macros +#define GENERIC_ASM_API (1) +#include "py/asmxtensa.h" + +#define N_XTENSA (1) +#define EXPORT_FUN(name) emit_native_xtensa_##name +#include "py/emitnative.c" + +#endif diff --git a/py/mkrules.mk b/py/mkrules.mk index fa7138695d..850c2aa3a6 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -46,10 +46,7 @@ vpath %.c . $(TOP) $(BUILD)/%.o: %.c $(call compile_c) -# List all native flags since the current build system doesn't have -# the MicroPython configuration available. However, these flags are -# needed to extract all qstrings -QSTR_GEN_EXTRA_CFLAGS += -DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB -DN_ARM -DN_XTENSA +QSTR_GEN_EXTRA_CFLAGS += -DNO_QSTR QSTR_GEN_EXTRA_CFLAGS += -I$(BUILD)/tmp vpath %.c . $(TOP) diff --git a/py/py.mk b/py/py.mk index 7c4cf82d82..a918135268 100644 --- a/py/py.mk +++ b/py/py.mk @@ -267,8 +267,8 @@ PY_O += $(BUILD)/$(BUILD)/frozen_mpy.o endif # Sources that may contain qstrings -SRC_QSTR_IGNORE = py/nlr% py/emitnx86% py/emitnx64% py/emitnthumb% py/emitnarm% py/emitnxtensa% -SRC_QSTR = $(SRC_MOD) $(filter-out $(SRC_QSTR_IGNORE),$(PY_CORE_O_BASENAME:.o=.c)) py/emitnative.c $(PY_EXTMOD_O_BASENAME:.o=.c) +SRC_QSTR_IGNORE = py/nlr% +SRC_QSTR = $(SRC_MOD) $(filter-out $(SRC_QSTR_IGNORE),$(PY_CORE_O_BASENAME:.o=.c)) $(PY_EXTMOD_O_BASENAME:.o=.c) # Anything that depends on FORCE will be considered out-of-date FORCE: @@ -295,28 +295,6 @@ $(HEADER_BUILD)/qstrdefs.generated.h: $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_C # that the function preludes are of a minimal and predictable form. $(PY_BUILD)/nlr%.o: CFLAGS += -Os -# emitters - -$(PY_BUILD)/emitnx64.o: CFLAGS += -DN_X64 -$(PY_BUILD)/emitnx64.o: py/emitnative.c - $(call compile_c) - -$(PY_BUILD)/emitnx86.o: CFLAGS += -DN_X86 -$(PY_BUILD)/emitnx86.o: py/emitnative.c - $(call compile_c) - -$(PY_BUILD)/emitnthumb.o: CFLAGS += -DN_THUMB -$(PY_BUILD)/emitnthumb.o: py/emitnative.c - $(call compile_c) - -$(PY_BUILD)/emitnarm.o: CFLAGS += -DN_ARM -$(PY_BUILD)/emitnarm.o: py/emitnative.c - $(call compile_c) - -$(PY_BUILD)/emitnxtensa.o: CFLAGS += -DN_XTENSA -$(PY_BUILD)/emitnxtensa.o: py/emitnative.c - $(call compile_c) - # optimising gc for speed; 5ms down to 4ms on pybv2 $(PY_BUILD)/gc.o: CFLAGS += $(CSUPEROPT) From 4ff05ae4e9b1f46a9bdf9322391e3b3599a1ad3e Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Apr 2018 15:24:10 +1000 Subject: [PATCH 533/828] esp32/machine_uart: Remove UART event queue object. This event queue has UART events posted to it and they need to be drained for it to operate without error. The queue is not used by the uPy UART class so it should be removed to prevent the IDF emitting errors. Fixes #3704. --- ports/esp32/machine_uart.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ports/esp32/machine_uart.c b/ports/esp32/machine_uart.c index 26cbc88fcd..474764b1b6 100644 --- a/ports/esp32/machine_uart.c +++ b/ports/esp32/machine_uart.c @@ -52,8 +52,6 @@ typedef struct _machine_uart_obj_t { STATIC const char *_parity_name[] = {"None", "1", "0"}; -QueueHandle_t UART_QUEUE[UART_NUM_MAX] = {}; - /******************************************************************************/ // MicroPython bindings for UART @@ -242,7 +240,7 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, uart_param_config(self->uart_num, &uartcfg); // RX and TX buffers are currently hardcoded at 256 bytes each (IDF minimum). - uart_driver_install(uart_num, 256, 256, 10, &UART_QUEUE[self->uart_num], 0); + uart_driver_install(uart_num, 256, 256, 0, NULL, 0); mp_map_t kw_args; mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); From 59dda7103855e2f85822f83ecbb835d66f12183d Mon Sep 17 00:00:00 2001 From: "Peter D. Gray" Date: Thu, 29 Mar 2018 15:03:17 -0400 Subject: [PATCH 534/828] stm32/main: Guard usb_mode lines in default boot.py by relevant #if. --- ports/stm32/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index fb3e843bba..120ab5b670 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -136,8 +136,10 @@ static const char fresh_boot_py[] = "import machine\r\n" "import pyb\r\n" "#pyb.main('main.py') # main script to run after this one\r\n" +#if MICROPY_HW_ENABLE_USB "#pyb.usb_mode('VCP+MSC') # act as a serial and a storage device\r\n" "#pyb.usb_mode('VCP+HID') # act as a serial device and a mouse\r\n" +#endif ; static const char fresh_main_py[] = From de9528d12c73d658406d1b11ff44d7a39596af01 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 11 Apr 2018 13:16:54 +1000 Subject: [PATCH 535/828] stm32/adc: Fix verification of ADC channel 16 for F411 MCUs. --- ports/stm32/adc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 3f38fa2ca2..3f00ad875e 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -137,7 +137,10 @@ static inline uint32_t adc_get_internal_channel(uint32_t channel) { } STATIC bool is_adcx_channel(int channel) { -#if defined(STM32F4) || defined(STM32F7) +#if defined(STM32F411xE) + // The HAL has an incorrect IS_ADC_CHANNEL macro for the F411 so we check for temp + return IS_ADC_CHANNEL(channel) || channel == ADC_CHANNEL_TEMPSENSOR; +#elif defined(STM32F4) || defined(STM32F7) return IS_ADC_CHANNEL(channel); #elif defined(STM32L4) ADC_HandleTypeDef handle; From 0096a4bd005606489a5b7fdfda8e2a60a1709e13 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 11 Apr 2018 13:20:58 +1000 Subject: [PATCH 536/828] tests/pyb/adc.py: Fix test so that it really does test ADC values. Reading into a bytearray will truncate values to 0xff so the assertions checking read_timed() would previously always succeed. Thanks to @peterhinch for finding this problem and providing the solution. --- tests/pyb/adc.py | 45 ++++++++++++++++++++++---------------------- tests/pyb/adc.py.exp | 3 ++- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/tests/pyb/adc.py b/tests/pyb/adc.py index 362ca326d2..7834c7520b 100644 --- a/tests/pyb/adc.py +++ b/tests/pyb/adc.py @@ -1,33 +1,34 @@ -from pyb import ADC -from pyb import Pin +from pyb import ADC, Timer -pin = Pin('X22', mode=Pin.IN, pull=Pin.PULL_DOWN) -adc = ADC('X22') -print(adc) +adct = ADC(16) # Temperature 930 -> 20C +print(adct) +adcv = ADC(17) # Voltage 1500 -> 3.3V +print(adcv) -# read single sample -val = adc.read() -assert val < 500 +# read single sample; 2.5V-5V is pass range +val = adcv.read() +assert val > 1000 and val < 2000 # timer for read_timed -tim = pyb.Timer(5, freq=500) +tim = Timer(5, freq=500) # read into bytearray -buf = bytearray(50) -adc.read_timed(buf, tim) +buf = bytearray(b'\xff' * 50) +adcv.read_timed(buf, tim) print(len(buf)) for i in buf: - assert i < 500 + assert i > 50 and i < 150 # read into arrays with different element sizes import array -ar = array.array('h', 25 * [0]) -adc.read_timed(ar, tim) -print(len(ar)) -for i in buf: - assert i < 500 -ar = array.array('i', 30 * [0]) -adc.read_timed(ar, tim) -print(len(ar)) -for i in buf: - assert i < 500 +arv = array.array('h', 25 * [0x7fff]) +adcv.read_timed(arv, tim) +print(len(arv)) +for i in arv: + assert i > 1000 and i < 2000 + +arv = array.array('i', 30 * [-1]) +adcv.read_timed(arv, tim) +print(len(arv)) +for i in arv: + assert i > 1000 and i < 2000 diff --git a/tests/pyb/adc.py.exp b/tests/pyb/adc.py.exp index 76f3914b03..1aae16fb01 100644 --- a/tests/pyb/adc.py.exp +++ b/tests/pyb/adc.py.exp @@ -1,4 +1,5 @@ - + + 50 25 30 From 4f40fa5cf4de7a8eabe073493e2df54c8a08ea89 Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Sun, 4 Mar 2018 09:07:40 +0000 Subject: [PATCH 537/828] stm32/adc: Add read_timed_multi() static method, with docs and tests. --- docs/library/pyb.ADC.rst | 53 ++++++++++++++++++- ports/stm32/adc.c | 107 +++++++++++++++++++++++++++++++++++++++ tests/pyb/adc.py | 28 ++++++++++ 3 files changed, 187 insertions(+), 1 deletion(-) diff --git a/docs/library/pyb.ADC.rst b/docs/library/pyb.ADC.rst index 58aae6129a..c2d09ad402 100644 --- a/docs/library/pyb.ADC.rst +++ b/docs/library/pyb.ADC.rst @@ -76,7 +76,58 @@ Methods for val in buf: # loop over all values print(val) # print the value out - This function does not allocate any memory. + This function does not allocate any heap memory. It has blocking behaviour: + it does not return to the calling program until the buffer is full. + + .. method:: ADC.read_timed_multi((adcx, adcy, ...), (bufx, bufy, ...), timer) + + This is a static method. It can be used to extract relative timing or + phase data from multiple ADC's. + + It reads analog values from multiple ADC's into buffers at a rate set by + the *timer* object. Each time the timer triggers a sample is rapidly + read from each ADC in turn. + + ADC and buffer instances are passed in tuples with each ADC having an + associated buffer. All buffers must be of the same type and length and + the number of buffers must equal the number of ADC's. + + Buffers can be ``bytearray`` or ``array.array`` for example. The ADC values + have 12-bit resolution and are stored directly into the buffer if its element + size is 16 bits or greater. If buffers have only 8-bit elements (eg a + ``bytearray``) then the sample resolution will be reduced to 8 bits. + + *timer* must be a Timer object. The timer must already be initialised + and running at the desired sampling frequency. + + Example reading 3 ADC's:: + + adc0 = pyb.ADC(pyb.Pin.board.X1) # Create ADC's + adc1 = pyb.ADC(pyb.Pin.board.X2) + adc2 = pyb.ADC(pyb.Pin.board.X3) + tim = pyb.Timer(8, freq=100) # Create timer + rx0 = array.array('H', (0 for i in range(100))) # ADC buffers of + rx1 = array.array('H', (0 for i in range(100))) # 100 16-bit words + rx2 = array.array('H', (0 for i in range(100))) + # read analog values into buffers at 100Hz (takes one second) + pyb.ADC.read_timed_multi((adc0, adc1, adc2), (rx0, rx1, rx2), tim) + for n in range(len(rx0)): + print(rx0[n], rx1[n], rx2[n]) + + This function does not allocate any heap memory. It has blocking behaviour: + it does not return to the calling program until the buffers are full. + + The function returns ``True`` if all samples were acquired with correct + timing. At high sample rates the time taken to acquire a set of samples + can exceed the timer period. In this case the function returns ``False``, + indicating a loss of precision in the sample interval. In extreme cases + samples may be missed. + + The maximum rate depends on factors including the data width and the + number of ADC's being read. In testing two ADC's were sampled at a timer + rate of 140KHz without overrun. Samples were missed at 180KHz. At high + sample rates disabling interrupts for the duration can reduce the risk + of sporadic data loss. The ADCAll Object ----------------- diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 3f00ad875e..ba1ca5ce59 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -450,9 +450,116 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_ } STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_obj, adc_read_timed); +// read_timed_multi((adcx, adcy, ...), (bufx, bufy, ...), timer) +// +// Read analog values from multiple ADC's into buffers at a rate set by the +// timer. The ADC values have 12-bit resolution and are stored directly into +// the corresponding buffer if its element size is 16 bits or greater, otherwise +// the sample resolution will be reduced to 8 bits. +// +// This function should not allocate any heap memory. +STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_in, mp_obj_t tim_in) { + size_t nadcs, nbufs; + mp_obj_t *adc_array, *buf_array; + mp_obj_get_array(adc_array_in, &nadcs, &adc_array); + mp_obj_get_array(buf_array_in, &nbufs, &buf_array); + + if (nadcs < 1) { + mp_raise_ValueError("need at least 1 ADC"); + } + if (nadcs != nbufs) { + mp_raise_ValueError("length of ADC and buffer lists differ"); + } + + // Get buf for first ADC, get word size, check other buffers match in type + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_array[0], &bufinfo, MP_BUFFER_WRITE); + size_t typesize = mp_binary_get_size('@', bufinfo.typecode, NULL); + for (uint array_index = 0; array_index < nbufs; array_index++) { + mp_buffer_info_t bufinfo_curr; + mp_get_buffer_raise(buf_array[array_index], &bufinfo_curr, MP_BUFFER_WRITE); + if ((bufinfo.len != bufinfo_curr.len) || (bufinfo.typecode != bufinfo_curr.typecode)) { + mp_raise_ValueError("size and type of buffers must match"); + } + } + + // Use the supplied timer object as the sampling time base + TIM_HandleTypeDef *tim; + tim = pyb_timer_get_handle(tim_in); + + // Start adc; this is slow so wait for it to start + pyb_obj_adc_t *adc0 = adc_array[0]; + adc_config_channel(&adc0->handle, adc0->channel); + HAL_ADC_Start(&adc0->handle); + // Wait for sample to complete and discard + #define READ_TIMED_TIMEOUT (10) // in ms + adc_wait_for_eoc_or_timeout(READ_TIMED_TIMEOUT); + // Read (and discard) value + uint value = ADCx->DR; + + // Ensure first sample is on a timer tick + __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE); + while (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) == RESET) { + } + __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE); + + // Overrun check: assume success + bool success = true; + size_t nelems = bufinfo.len / typesize; + for (size_t elem_index = 0; elem_index < nelems; elem_index++) { + if (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) != RESET) { + // Timer has already triggered + success = false; + } else { + // Wait for the timer to trigger so we sample at the correct frequency + while (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) == RESET) { + } + } + __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE); + + for (size_t array_index = 0; array_index < nadcs; array_index++) { + pyb_obj_adc_t *adc = adc_array[array_index]; + // configure the ADC channel + adc_config_channel(&adc->handle, adc->channel); + // for the first sample we need to turn the ADC on + // ADC is started: set the "start sample" bit + #if defined(STM32F4) || defined(STM32F7) + ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART; + #elif defined(STM32L4) + SET_BIT(ADCx->CR, ADC_CR_ADSTART); + #else + #error Unsupported processor + #endif + // wait for sample to complete + #define READ_TIMED_TIMEOUT (10) // in ms + adc_wait_for_eoc_or_timeout(READ_TIMED_TIMEOUT); + + // read value + value = ADCx->DR; + + // store values in buffer + if (typesize == 1) { + value >>= 4; + } + mp_buffer_info_t bufinfo_curr; // Get buf for current ADC + mp_get_buffer_raise(buf_array[array_index], &bufinfo_curr, MP_BUFFER_WRITE); + mp_binary_set_val_array_from_int(bufinfo_curr.typecode, bufinfo_curr.buf, elem_index, value); + } + } + + // Turn the ADC off + adc0 = adc_array[0]; + HAL_ADC_Stop(&adc0->handle); + + return mp_obj_new_bool(success); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_multi_fun_obj, adc_read_timed_multi); +STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(adc_read_timed_multi_obj, MP_ROM_PTR(&adc_read_timed_multi_fun_obj)); + STATIC const mp_rom_map_elem_t adc_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&adc_read_obj) }, { MP_ROM_QSTR(MP_QSTR_read_timed), MP_ROM_PTR(&adc_read_timed_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_timed_multi), MP_ROM_PTR(&adc_read_timed_multi_obj) }, }; STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table); diff --git a/tests/pyb/adc.py b/tests/pyb/adc.py index 7834c7520b..0bd9b9d53a 100644 --- a/tests/pyb/adc.py +++ b/tests/pyb/adc.py @@ -32,3 +32,31 @@ adcv.read_timed(arv, tim) print(len(arv)) for i in arv: assert i > 1000 and i < 2000 + +# Test read_timed_multi +arv = bytearray(b'\xff'*50) +art = bytearray(b'\xff'*50) +ADC.read_timed_multi((adcv, adct), (arv, art), tim) +for i in arv: + assert i > 60 and i < 125 +# Wide range: unsure of accuracy of temp sensor. +for i in art: + assert i > 15 and i < 200 + +arv = array.array('i', 25 * [-1]) +art = array.array('i', 25 * [-1]) +ADC.read_timed_multi((adcv, adct), (arv, art), tim) +for i in arv: + assert i > 1000 and i < 2000 +# Wide range: unsure of accuracy of temp sensor. +for i in art: + assert i > 50 and i < 2000 + +arv = array.array('h', 25 * [0x7fff]) +art = array.array('h', 25 * [0x7fff]) +ADC.read_timed_multi((adcv, adct), (arv, art), tim) +for i in arv: + assert i > 1000 and i < 2000 +# Wide range: unsure of accuracy of temp sensor. +for i in art: + assert i > 50 and i < 2000 From aebd9701a78d267cb264d400804b02c5b7a00e9a Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 11 Apr 2018 14:08:23 +1000 Subject: [PATCH 538/828] stm32/adc: Optimise read_timed_multi() by caching buffer pointers. --- docs/library/pyb.ADC.rst | 7 ++++--- ports/stm32/adc.c | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/library/pyb.ADC.rst b/docs/library/pyb.ADC.rst index c2d09ad402..1256c6a3c1 100644 --- a/docs/library/pyb.ADC.rst +++ b/docs/library/pyb.ADC.rst @@ -125,9 +125,10 @@ Methods The maximum rate depends on factors including the data width and the number of ADC's being read. In testing two ADC's were sampled at a timer - rate of 140KHz without overrun. Samples were missed at 180KHz. At high - sample rates disabling interrupts for the duration can reduce the risk - of sporadic data loss. + rate of 210kHz without overrun. Samples were missed at 215kHz. For three + ADC's the limit is around 140kHz, and for four it is around 110kHz. + At high sample rates disabling interrupts for the duration can reduce the + risk of sporadic data loss. The ADCAll Object ----------------- diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index ba1ca5ce59..f765870d5f 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -475,12 +475,14 @@ STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_i mp_buffer_info_t bufinfo; mp_get_buffer_raise(buf_array[0], &bufinfo, MP_BUFFER_WRITE); size_t typesize = mp_binary_get_size('@', bufinfo.typecode, NULL); + void *bufptrs[nbufs]; for (uint array_index = 0; array_index < nbufs; array_index++) { mp_buffer_info_t bufinfo_curr; mp_get_buffer_raise(buf_array[array_index], &bufinfo_curr, MP_BUFFER_WRITE); if ((bufinfo.len != bufinfo_curr.len) || (bufinfo.typecode != bufinfo_curr.typecode)) { mp_raise_ValueError("size and type of buffers must match"); } + bufptrs[array_index] = bufinfo_curr.buf; } // Use the supplied timer object as the sampling time base @@ -541,9 +543,7 @@ STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_i if (typesize == 1) { value >>= 4; } - mp_buffer_info_t bufinfo_curr; // Get buf for current ADC - mp_get_buffer_raise(buf_array[array_index], &bufinfo_curr, MP_BUFFER_WRITE); - mp_binary_set_val_array_from_int(bufinfo_curr.typecode, bufinfo_curr.buf, elem_index, value); + mp_binary_set_val_array_from_int(bufinfo.typecode, bufptrs[array_index], elem_index, value); } } From b30e0d2f2683a809ae393dd402aad89a62a22df3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Apr 2018 22:25:55 +1000 Subject: [PATCH 539/828] stm32/dac: Add buffering argument to constructor and init() method. This can be used to select the output buffer behaviour of the DAC. The default values are chosen to retain backwards compatibility with existing behaviour. Thanks to @peterhinch for the initial idea to add this feature. --- docs/library/pyb.DAC.rst | 21 ++++++++++++++++++--- ports/stm32/dac.c | 24 ++++++++++++++++++++---- tests/pyb/dac.py | 4 ++++ 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/docs/library/pyb.DAC.rst b/docs/library/pyb.DAC.rst index fd786b63b6..3e236a3da9 100644 --- a/docs/library/pyb.DAC.rst +++ b/docs/library/pyb.DAC.rst @@ -49,7 +49,7 @@ To output a continuous sine-wave at 12-bit resolution:: Constructors ------------ -.. class:: pyb.DAC(port, bits=8) +.. class:: pyb.DAC(port, bits=8, \*, buffering=None) Construct a new DAC object. @@ -60,12 +60,27 @@ Constructors The maximum value for the write and write_timed methods will be 2\*\*``bits``-1. + The *buffering* parameter selects the behaviour of the DAC op-amp output + buffer, whose purpose is to reduce the output impedance. It can be + ``None`` to select the default (buffering enabled for :meth:`DAC.noise`, + :meth:`DAC.triangle` and :meth:`DAC.write_timed`, and disabled for + :meth:`DAC.write`), ``False`` to disable buffering completely, or ``True`` + to enable output buffering. + + When buffering is enabled the DAC pin can drive loads down to 5KΩ. + Otherwise it has an output impedance of 15KΩ maximum: consequently + to achieve a 1% accuracy without buffering requires the applied load + to be less than 1.5MΩ. Using the buffer incurs a penalty in accuracy, + especially near the extremes of range. + Methods ------- -.. method:: DAC.init(bits=8) +.. method:: DAC.init(bits=8, \*, buffering=None) - Reinitialise the DAC. ``bits`` can be 8 or 12. + Reinitialise the DAC. *bits* can be 8 or 12. *buffering* can be + ``None``, ``False`` or ``True`; see above constructor for the meaning + of this parameter. .. method:: DAC.deinit() diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c index bce30dbc7e..04acfb8aa1 100644 --- a/ports/stm32/dac.c +++ b/ports/stm32/dac.c @@ -143,11 +143,14 @@ typedef struct _pyb_dac_obj_t { uint16_t pin; // GPIO_PIN_4 or GPIO_PIN_5 uint8_t bits; // 8 or 12 uint8_t state; + uint8_t outbuf_single; + uint8_t outbuf_waveform; } pyb_dac_obj_t; STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_buffering, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, }; // parse args @@ -194,6 +197,19 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp mp_raise_ValueError("unsupported bits"); } + // set output buffer config + if (args[1].u_obj == mp_const_none) { + // due to legacy, default values differ for single and waveform outputs + self->outbuf_single = DAC_OUTPUTBUFFER_DISABLE; + self->outbuf_waveform = DAC_OUTPUTBUFFER_ENABLE; + } else if (mp_obj_is_true(args[1].u_obj)) { + self->outbuf_single = DAC_OUTPUTBUFFER_ENABLE; + self->outbuf_waveform = DAC_OUTPUTBUFFER_ENABLE; + } else { + self->outbuf_single = DAC_OUTPUTBUFFER_DISABLE; + self->outbuf_waveform = DAC_OUTPUTBUFFER_DISABLE; + } + // reset state of DAC self->state = DAC_STATE_RESET; @@ -289,7 +305,7 @@ STATIC mp_obj_t pyb_dac_noise(mp_obj_t self_in, mp_obj_t freq) { // configure DAC to trigger via TIM6 DAC_ChannelConfTypeDef config; config.DAC_Trigger = DAC_TRIGGER_T6_TRGO; - config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + config.DAC_OutputBuffer = self->outbuf_waveform; HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); self->state = DAC_STATE_BUILTIN_WAVEFORM; } @@ -319,7 +335,7 @@ STATIC mp_obj_t pyb_dac_triangle(mp_obj_t self_in, mp_obj_t freq) { // configure DAC to trigger via TIM6 DAC_ChannelConfTypeDef config; config.DAC_Trigger = DAC_TRIGGER_T6_TRGO; - config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + config.DAC_OutputBuffer = self->outbuf_waveform; HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); self->state = DAC_STATE_BUILTIN_WAVEFORM; } @@ -342,7 +358,7 @@ STATIC mp_obj_t pyb_dac_write(mp_obj_t self_in, mp_obj_t val) { if (self->state != DAC_STATE_WRITE_SINGLE) { DAC_ChannelConfTypeDef config; config.DAC_Trigger = DAC_TRIGGER_NONE; - config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE; + config.DAC_OutputBuffer = self->outbuf_single; HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); self->state = DAC_STATE_WRITE_SINGLE; } @@ -454,7 +470,7 @@ mp_obj_t pyb_dac_write_timed(size_t n_args, const mp_obj_t *pos_args, mp_map_t * if (self->state != DAC_STATE_DMA_WAVEFORM + dac_trigger) { DAC_ChannelConfTypeDef config; config.DAC_Trigger = dac_trigger; - config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + config.DAC_OutputBuffer = self->outbuf_waveform; HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); self->state = DAC_STATE_DMA_WAVEFORM + dac_trigger; } diff --git a/tests/pyb/dac.py b/tests/pyb/dac.py index 6f03bbc64d..ca68ec7098 100644 --- a/tests/pyb/dac.py +++ b/tests/pyb/dac.py @@ -12,3 +12,7 @@ dac.write(0) dac.write_timed(bytearray(10), 100, mode=pyb.DAC.NORMAL) pyb.delay(20) dac.write(0) + +# test buffering arg +dac = pyb.DAC(1, buffering=True) +dac.write(0) From 06807c1bde6885a070be78e63271ad596e31c06c Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 11 Apr 2018 14:28:06 +1000 Subject: [PATCH 540/828] stm32/adc: Factor code to optimise adc_read_channel and adc_read. Saves 200 bytes of code space. --- ports/stm32/adc.c | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index f765870d5f..dea69a7273 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -109,6 +109,9 @@ #error Unsupported processor #endif +// Timeout for waiting for end-of-conversion, in ms +#define EOC_TIMEOUT (10) + /* Core temperature sensor definitions */ #define CORE_TEMP_V25 (943) /* (0.76v/3.3v)*(2^ADC resoultion) */ #define CORE_TEMP_AVG_SLOPE (3) /* (2.5mv/3.3v)*(2^ADC resoultion) */ @@ -261,16 +264,16 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) } STATIC uint32_t adc_read_channel(ADC_HandleTypeDef *adcHandle) { - uint32_t rawValue = 0; - HAL_ADC_Start(adcHandle); - if (HAL_ADC_PollForConversion(adcHandle, 10) == HAL_OK - && (HAL_ADC_GetState(adcHandle) & HAL_ADC_STATE_REG_EOC) == HAL_ADC_STATE_REG_EOC) { - rawValue = HAL_ADC_GetValue(adcHandle); - } + adc_wait_for_eoc_or_timeout(EOC_TIMEOUT); + uint32_t value = ADCx->DR; HAL_ADC_Stop(adcHandle); + return value; +} - return rawValue; +STATIC uint32_t adc_config_and_read_channel(ADC_HandleTypeDef *adcHandle, uint32_t channel) { + adc_config_channel(adcHandle, channel); + return adc_read_channel(adcHandle); } /******************************************************************************/ @@ -334,10 +337,7 @@ STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ /// will be between 0 and 4095. STATIC mp_obj_t adc_read(mp_obj_t self_in) { pyb_obj_adc_t *self = self_in; - - adc_config_channel(&self->handle, self->channel); - uint32_t data = adc_read_channel(&self->handle); - return mp_obj_new_int(data); + return mp_obj_new_int(adc_config_and_read_channel(&self->handle, self->channel)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read); @@ -423,8 +423,7 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_ } // wait for sample to complete - #define READ_TIMED_TIMEOUT (10) // in ms - adc_wait_for_eoc_or_timeout(READ_TIMED_TIMEOUT); + adc_wait_for_eoc_or_timeout(EOC_TIMEOUT); // read value uint value = ADCx->DR; @@ -494,8 +493,7 @@ STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_i adc_config_channel(&adc0->handle, adc0->channel); HAL_ADC_Start(&adc0->handle); // Wait for sample to complete and discard - #define READ_TIMED_TIMEOUT (10) // in ms - adc_wait_for_eoc_or_timeout(READ_TIMED_TIMEOUT); + adc_wait_for_eoc_or_timeout(EOC_TIMEOUT); // Read (and discard) value uint value = ADCx->DR; @@ -533,8 +531,7 @@ STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_i #error Unsupported processor #endif // wait for sample to complete - #define READ_TIMED_TIMEOUT (10) // in ms - adc_wait_for_eoc_or_timeout(READ_TIMED_TIMEOUT); + adc_wait_for_eoc_or_timeout(EOC_TIMEOUT); // read value value = ADCx->DR; @@ -640,11 +637,6 @@ void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_m HAL_ADC_Init(adcHandle); } -uint32_t adc_config_and_read_channel(ADC_HandleTypeDef *adcHandle, uint32_t channel) { - adc_config_channel(adcHandle, channel); - return adc_read_channel(adcHandle); -} - int adc_get_resolution(ADC_HandleTypeDef *adcHandle) { uint32_t res_reg = ADC_GET_RESOLUTION(adcHandle); From 1d6c155d6ac1c335e66b427cbead55b4217fc097 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 11 Apr 2018 14:29:37 +1000 Subject: [PATCH 541/828] stm32/adc: Fix config of EOC selection and Ext-Trig for ADC periph. A value of DISABLE for EOCSelection is invalid. This would have been interpreted instead as ADC_EOC_SEQ_CONV, but really it should be ADC_EOC_SINGLE_CONV for the uses in this code. So this has been fixed. ExternalTrigConv should be ADC_SOFTWARE_START because all ADC conversions are started by software. This is now fixed. --- ports/stm32/adc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index dea69a7273..5875430bdf 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -217,8 +217,8 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { #if defined(STM32F4) || defined(STM32F7) adcHandle->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; adcHandle->Init.ScanConvMode = DISABLE; - adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1; - adcHandle->Init.EOCSelection = DISABLE; + adcHandle->Init.ExternalTrigConv = ADC_SOFTWARE_START; + adcHandle->Init.EOCSelection = ADC_EOC_SINGLE_CONV; #elif defined(STM32L4) adcHandle->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; adcHandle->Init.ScanConvMode = ADC_SCAN_DISABLE; @@ -618,15 +618,15 @@ void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_m adcHandle->Init.DataAlign = ADC_DATAALIGN_RIGHT; adcHandle->Init.NbrOfConversion = 1; adcHandle->Init.DMAContinuousRequests = DISABLE; - adcHandle->Init.EOCSelection = DISABLE; + adcHandle->Init.EOCSelection = ADC_EOC_SINGLE_CONV; #if defined(STM32F4) || defined(STM32F7) adcHandle->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; adcHandle->Init.ScanConvMode = DISABLE; - adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1; + adcHandle->Init.ExternalTrigConv = ADC_SOFTWARE_START; #elif defined(STM32L4) adcHandle->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2; adcHandle->Init.ScanConvMode = ADC_SCAN_DISABLE; - adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIG_T1_CC1; + adcHandle->Init.ExternalTrigConv = ADC_SOFTWARE_START; adcHandle->Init.LowPowerAutoWait = DISABLE; adcHandle->Init.Overrun = ADC_OVR_DATA_PRESERVED; adcHandle->Init.OversamplingMode = DISABLE; From f1073e747d0489154942a0d0e0585bc6943df448 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 11 Apr 2018 14:46:13 +1000 Subject: [PATCH 542/828] stm32/adc: Factor common ADC init code into adcx_init_periph(). The only configuration that changes with this patch is that on L4 MCUs the clock prescaler changed from ADC_CLOCK_ASYNC_DIV2 to ADC_CLOCK_ASYNC_DIV1 for the ADCAll object. This should be ok. --- ports/stm32/adc.c | 94 +++++++++++++++++------------------------------ 1 file changed, 33 insertions(+), 61 deletions(-) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 5875430bdf..9f126650b9 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -179,6 +179,36 @@ STATIC void adcx_clock_enable(void) { #endif } +STATIC void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) { + adcx_clock_enable(); + + adch->Instance = ADCx; + adch->Init.Resolution = resolution; + adch->Init.ContinuousConvMode = DISABLE; + adch->Init.DiscontinuousConvMode = DISABLE; + adch->Init.NbrOfDiscConversion = 0; + adch->Init.DataAlign = ADC_DATAALIGN_RIGHT; + adch->Init.NbrOfConversion = 1; + adch->Init.DMAContinuousRequests = DISABLE; + adch->Init.EOCSelection = ADC_EOC_SINGLE_CONV; + adch->Init.ExternalTrigConv = ADC_SOFTWARE_START; + adch->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; + #if defined(STM32F4) || defined(STM32F7) + adch->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; + adch->Init.ScanConvMode = DISABLE; + #elif defined(STM32L4) + adch->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; + adch->Init.ScanConvMode = ADC_SCAN_DISABLE; + adch->Init.LowPowerAutoWait = DISABLE; + adch->Init.Overrun = ADC_OVR_DATA_PRESERVED; + adch->Init.OversamplingMode = DISABLE; + #else + #error Unsupported processor + #endif + + HAL_ADC_Init(adch); +} + STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { if (!is_adcx_channel(adc_obj->channel)) { return; @@ -202,42 +232,12 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { HAL_GPIO_Init(pin->gpio, &GPIO_InitStructure); } - adcx_clock_enable(); - - ADC_HandleTypeDef *adcHandle = &adc_obj->handle; - adcHandle->Instance = ADCx; - adcHandle->Init.ContinuousConvMode = DISABLE; - adcHandle->Init.DiscontinuousConvMode = DISABLE; - adcHandle->Init.NbrOfDiscConversion = 0; - adcHandle->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; - adcHandle->Init.DataAlign = ADC_DATAALIGN_RIGHT; - adcHandle->Init.NbrOfConversion = 1; - adcHandle->Init.DMAContinuousRequests = DISABLE; - adcHandle->Init.Resolution = ADC_RESOLUTION_12B; -#if defined(STM32F4) || defined(STM32F7) - adcHandle->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; - adcHandle->Init.ScanConvMode = DISABLE; - adcHandle->Init.ExternalTrigConv = ADC_SOFTWARE_START; - adcHandle->Init.EOCSelection = ADC_EOC_SINGLE_CONV; -#elif defined(STM32L4) - adcHandle->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; - adcHandle->Init.ScanConvMode = ADC_SCAN_DISABLE; - adcHandle->Init.EOCSelection = ADC_EOC_SINGLE_CONV; - adcHandle->Init.ExternalTrigConv = ADC_SOFTWARE_START; - adcHandle->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; - adcHandle->Init.LowPowerAutoWait = DISABLE; - adcHandle->Init.Overrun = ADC_OVR_DATA_PRESERVED; - adcHandle->Init.OversamplingMode = DISABLE; -#else - #error Unsupported processor -#endif - - HAL_ADC_Init(adcHandle); + adcx_init_periph(&adc_obj->handle, ADC_RESOLUTION_12B); #if defined(STM32L4) ADC_MultiModeTypeDef multimode; multimode.Mode = ADC_MODE_INDEPENDENT; - if (HAL_ADCEx_MultiModeConfigChannel(adcHandle, &multimode) != HAL_OK) + if (HAL_ADCEx_MultiModeConfigChannel(&adc_obj->handle, &multimode) != HAL_OK) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Can not set multimode on ADC1 channel: %d", adc_obj->channel)); } @@ -606,35 +606,7 @@ void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_m } } - adcx_clock_enable(); - - ADC_HandleTypeDef *adcHandle = &adc_all->handle; - adcHandle->Instance = ADCx; - adcHandle->Init.Resolution = resolution; - adcHandle->Init.ContinuousConvMode = DISABLE; - adcHandle->Init.DiscontinuousConvMode = DISABLE; - adcHandle->Init.NbrOfDiscConversion = 0; - adcHandle->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; - adcHandle->Init.DataAlign = ADC_DATAALIGN_RIGHT; - adcHandle->Init.NbrOfConversion = 1; - adcHandle->Init.DMAContinuousRequests = DISABLE; - adcHandle->Init.EOCSelection = ADC_EOC_SINGLE_CONV; -#if defined(STM32F4) || defined(STM32F7) - adcHandle->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; - adcHandle->Init.ScanConvMode = DISABLE; - adcHandle->Init.ExternalTrigConv = ADC_SOFTWARE_START; -#elif defined(STM32L4) - adcHandle->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2; - adcHandle->Init.ScanConvMode = ADC_SCAN_DISABLE; - adcHandle->Init.ExternalTrigConv = ADC_SOFTWARE_START; - adcHandle->Init.LowPowerAutoWait = DISABLE; - adcHandle->Init.Overrun = ADC_OVR_DATA_PRESERVED; - adcHandle->Init.OversamplingMode = DISABLE; -#else - #error Unsupported processor -#endif - - HAL_ADC_Init(adcHandle); + adcx_init_periph(&adc_all->handle, resolution); } int adc_get_resolution(ADC_HandleTypeDef *adcHandle) { From 0041396f05bc1f43657c343df6b291fc4bbdc901 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 11 Apr 2018 16:14:58 +1000 Subject: [PATCH 543/828] stm32/pin: In pin AF object, remove union of periph ptr types. The individual union members (like SPI, I2C) are never used, only the generic "reg" entry is. And the union names can clash with macro definitions in the HAL so better to remove them. --- ports/stm32/boards/stm32f4xx_prefix.c | 2 +- ports/stm32/pin.h | 7 +------ ports/stm32/pin_defs_stm32.h | 12 ------------ ports/teensy/mk20dx256_prefix.c | 2 +- ports/teensy/pin_defs_teensy.h | 6 ------ 5 files changed, 3 insertions(+), 26 deletions(-) diff --git a/ports/stm32/boards/stm32f4xx_prefix.c b/ports/stm32/boards/stm32f4xx_prefix.c index f4ffdab68e..3bcd6e6410 100644 --- a/ports/stm32/boards/stm32f4xx_prefix.c +++ b/ports/stm32/boards/stm32f4xx_prefix.c @@ -14,7 +14,7 @@ .fn = AF_FN_ ## af_fn, \ .unit = (af_unit), \ .type = AF_PIN_TYPE_ ## af_fn ## _ ## af_type, \ - .af_fn = (af_ptr) \ + .reg = (af_ptr) \ } #define PIN(p_port, p_pin, p_af, p_adc_num, p_adc_channel) \ diff --git a/ports/stm32/pin.h b/ports/stm32/pin.h index b0e05256fe..ea57b0a274 100644 --- a/ports/stm32/pin.h +++ b/ports/stm32/pin.h @@ -39,12 +39,7 @@ typedef struct { uint8_t fn; uint8_t unit; uint8_t type; - - union { - void *reg; - - PIN_DEFS_PORT_AF_UNION - }; + void *reg; // The peripheral associated with this AF } pin_af_obj_t; typedef struct { diff --git a/ports/stm32/pin_defs_stm32.h b/ports/stm32/pin_defs_stm32.h index c5b2862835..feaf56ae97 100644 --- a/ports/stm32/pin_defs_stm32.h +++ b/ports/stm32/pin_defs_stm32.h @@ -115,17 +115,5 @@ enum { PIN_ADC3 = (1 << 2), }; -// Note that SPI and I2S are really the same peripheral as far as the HAL -// is concerned, so there is no I2S_TypeDef. -// We use void* for SDMMC because not all MCUs have the SDMMC_TypeDef type. -#define PIN_DEFS_PORT_AF_UNION \ - TIM_TypeDef *TIM; \ - I2C_TypeDef *I2C; \ - USART_TypeDef *USART; \ - USART_TypeDef *UART; \ - SPI_TypeDef *SPI;\ - SPI_TypeDef *I2S; \ - void *SDMMC; \ - typedef GPIO_TypeDef pin_gpio_t; diff --git a/ports/teensy/mk20dx256_prefix.c b/ports/teensy/mk20dx256_prefix.c index d8e7480b58..58ab07d6ec 100644 --- a/ports/teensy/mk20dx256_prefix.c +++ b/ports/teensy/mk20dx256_prefix.c @@ -15,7 +15,7 @@ .fn = AF_FN_ ## af_fn, \ .unit = (af_unit), \ .type = AF_PIN_TYPE_ ## af_fn ## _ ## af_type, \ - .af_fn = (af_ptr) \ + .reg = (af_ptr) \ } #define PIN(p_port, p_pin, p_num_af, p_af, p_adc_num, p_adc_channel) \ diff --git a/ports/teensy/pin_defs_teensy.h b/ports/teensy/pin_defs_teensy.h index 54a6055f1a..d3a700be21 100644 --- a/ports/teensy/pin_defs_teensy.h +++ b/ports/teensy/pin_defs_teensy.h @@ -40,10 +40,4 @@ enum { AF_PIN_TYPE_UART_RTS, }; -#define PIN_DEFS_PORT_AF_UNION \ - FTM_TypeDef *FTM; \ - I2C_TypeDef *I2C; \ - UART_TypeDef *UART; \ - SPI_TypeDef *SPI; - typedef GPIO_TypeDef pin_gpio_t; From a7ebac2eaed7eb0da362568b9333339634f1da1d Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 11 Apr 2018 16:27:48 +1000 Subject: [PATCH 544/828] stm32/can: Allow CAN pins to be configured per board. This patch allows a given board to configure which pins are used for the CAN peripherals, in a similar way to all the other bus peripherals (I2C, UART, SPI). To enable CAN on a board the mpconfigboard.h file should define (for example): #define MICROPY_HW_CAN1_TX (pin_B9) #define MICROPY_HW_CAN1_RX (pin_B8) #define MICROPY_HW_CAN2_TX (pin_B13) #define MICROPY_HW_CAN2_RX (pin_B12) And the board config file should no longer define MICROPY_HW_ENABLE_CAN. --- ports/stm32/boards/CERB40/mpconfigboard.h | 7 +++- ports/stm32/boards/CERB40/pins.csv | 2 ++ .../boards/NUCLEO_F429ZI/mpconfigboard.h | 7 +++- .../boards/NUCLEO_F746ZG/mpconfigboard.h | 7 +++- .../boards/NUCLEO_F767ZI/mpconfigboard.h | 7 +++- .../stm32/boards/OLIMEX_E407/mpconfigboard.h | 7 +++- ports/stm32/boards/PYBV10/mpconfigboard.h | 9 +++-- ports/stm32/boards/PYBV11/mpconfigboard.h | 9 +++-- ports/stm32/boards/PYBV3/mpconfigboard.h | 7 +++- ports/stm32/boards/PYBV4/mpconfigboard.h | 9 +++-- .../boards/STM32F429DISC/mpconfigboard.h | 7 +++- ports/stm32/boards/STM32F439/mpconfigboard.h | 7 +++- .../stm32/boards/STM32F4DISC/mpconfigboard.h | 7 +++- .../boards/STM32F769DISC/mpconfigboard.h | 7 +++- ports/stm32/boards/STM32F769DISC/pins.csv | 2 ++ .../stm32/boards/STM32F7DISC/mpconfigboard.h | 7 +++- ports/stm32/boards/STM32F7DISC/pins.csv | 2 ++ .../boards/STM32L476DISC/mpconfigboard.h | 5 ++- ports/stm32/boards/make-pins.py | 2 ++ ports/stm32/can.c | 35 ++++++++----------- ports/stm32/mpconfigboard_common.h | 12 ++++--- ports/stm32/pin_defs_stm32.h | 4 +++ ports/stm32/stm32_it.c | 6 ++-- 23 files changed, 126 insertions(+), 48 deletions(-) diff --git a/ports/stm32/boards/CERB40/mpconfigboard.h b/ports/stm32/boards/CERB40/mpconfigboard.h index fdc7c01205..7c166922be 100644 --- a/ports/stm32/boards/CERB40/mpconfigboard.h +++ b/ports/stm32/boards/CERB40/mpconfigboard.h @@ -5,7 +5,6 @@ #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (1) #define MICROPY_HW_ENABLE_USB (1) // HSE is 12MHz @@ -50,6 +49,12 @@ #define MICROPY_HW_SPI3_MISO (pin_B4) #define MICROPY_HW_SPI3_MOSI (pin_B5) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + // The Cerb40 has No LEDs // The Cerb40 has No SDCard diff --git a/ports/stm32/boards/CERB40/pins.csv b/ports/stm32/boards/CERB40/pins.csv index 411031e8f5..da759f212e 100644 --- a/ports/stm32/boards/CERB40/pins.csv +++ b/ports/stm32/boards/CERB40/pins.csv @@ -44,3 +44,5 @@ UART3_TX,PD8 UART3_RX,PD9 UART3_RTS,PD12 UART3_CTS,PD11 +CAN2_TX,PB13 +CAN2_RX,PB12 diff --git a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h index ae7f822256..17883a1920 100644 --- a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h @@ -5,7 +5,6 @@ #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_CAN (1) #define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz @@ -59,6 +58,12 @@ #define MICROPY_HW_SPI5_MISO (pin_F8) #define MICROPY_HW_SPI5_MOSI (pin_F9) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_C13) #define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) diff --git a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h index 42beb4d9bf..a9fbea5766 100644 --- a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h @@ -11,7 +11,6 @@ #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (1) #define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz @@ -53,6 +52,12 @@ #define MICROPY_HW_SPI3_MISO (pin_B4) #define MICROPY_HW_SPI3_MOSI (pin_B5) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_C13) #define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) diff --git a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h index 4f9d41f1b1..7de4c33639 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h @@ -11,7 +11,6 @@ #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (1) #define MICROPY_HW_ENABLE_USB (1) // HSE is 25MHz @@ -53,6 +52,12 @@ #define MICROPY_HW_SPI3_MISO (pin_B4) #define MICROPY_HW_SPI3_MOSI (pin_B5) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_C13) #define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) diff --git a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h index 1bdb25a9ea..a56f6f79df 100644 --- a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h +++ b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h @@ -7,7 +7,6 @@ #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (1) #define MICROPY_HW_ENABLE_USB (1) // HSE is 12MHz @@ -53,6 +52,12 @@ #define MICROPY_HW_SPI2_MISO (pin_B14) #define MICROPY_HW_SPI2_MOSI (pin_B15) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_A0) #define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) diff --git a/ports/stm32/boards/PYBV10/mpconfigboard.h b/ports/stm32/boards/PYBV10/mpconfigboard.h index 5d158e6b1c..3439f5a0fb 100644 --- a/ports/stm32/boards/PYBV10/mpconfigboard.h +++ b/ports/stm32/boards/PYBV10/mpconfigboard.h @@ -10,7 +10,6 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (1) #define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz @@ -66,8 +65,12 @@ #define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8 // CAN busses -#define MICROPY_HW_CAN1_NAME "YA" // CAN1 on RX,TX = Y3,Y4 = PB8,PB9 -#define MICROPY_HW_CAN2_NAME "YB" // CAN2 on RX,TX = Y5,Y6 = PB12,PB13 +#define MICROPY_HW_CAN1_NAME "YA" +#define MICROPY_HW_CAN1_TX (pin_B9) // Y4 +#define MICROPY_HW_CAN1_RX (pin_B8) // Y3 +#define MICROPY_HW_CAN2_NAME "YB" +#define MICROPY_HW_CAN2_TX (pin_B13) // Y6 +#define MICROPY_HW_CAN2_RX (pin_B12) // Y5 // 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/ports/stm32/boards/PYBV11/mpconfigboard.h b/ports/stm32/boards/PYBV11/mpconfigboard.h index 71ff528487..2c75d0e64f 100644 --- a/ports/stm32/boards/PYBV11/mpconfigboard.h +++ b/ports/stm32/boards/PYBV11/mpconfigboard.h @@ -10,7 +10,6 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (1) #define MICROPY_HW_ENABLE_USB (1) // HSE is 12MHz @@ -66,8 +65,12 @@ #define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8 // CAN busses -#define MICROPY_HW_CAN1_NAME "YA" // CAN1 on RX,TX = Y3,Y4 = PB8,PB9 -#define MICROPY_HW_CAN2_NAME "YB" // CAN2 on RX,TX = Y5,Y6 = PB12,PB13 +#define MICROPY_HW_CAN1_NAME "YA" +#define MICROPY_HW_CAN1_TX (pin_B9) // Y4 +#define MICROPY_HW_CAN1_RX (pin_B8) // Y3 +#define MICROPY_HW_CAN2_NAME "YB" +#define MICROPY_HW_CAN2_TX (pin_B13) // Y6 +#define MICROPY_HW_CAN2_RX (pin_B12) // Y5 // 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/ports/stm32/boards/PYBV3/mpconfigboard.h b/ports/stm32/boards/PYBV3/mpconfigboard.h index d2e7dbe20a..3e457c5e21 100644 --- a/ports/stm32/boards/PYBV3/mpconfigboard.h +++ b/ports/stm32/boards/PYBV3/mpconfigboard.h @@ -9,7 +9,6 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (1) #define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz @@ -57,6 +56,12 @@ #define MICROPY_HW_SPI2_MISO (pin_B14) // Y7 #define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8 +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) // Y4 +#define MICROPY_HW_CAN1_RX (pin_B8) // Y3 +#define MICROPY_HW_CAN2_TX (pin_B13) // Y6 +#define MICROPY_HW_CAN2_RX (pin_B12) // Y5 + // USRSW has no pullup or pulldown, and pressing the switch makes the input go low #define MICROPY_HW_USRSW_PIN (pin_A13) #define MICROPY_HW_USRSW_PULL (GPIO_PULLUP) diff --git a/ports/stm32/boards/PYBV4/mpconfigboard.h b/ports/stm32/boards/PYBV4/mpconfigboard.h index c6d9ad9ac7..8c05644f6d 100644 --- a/ports/stm32/boards/PYBV4/mpconfigboard.h +++ b/ports/stm32/boards/PYBV4/mpconfigboard.h @@ -10,7 +10,6 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (1) #define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz @@ -63,8 +62,12 @@ #define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8 // CAN busses -#define MICROPY_HW_CAN1_NAME "YA" // CAN1 on RX,TX = Y3,Y4 = PB8,PB9 -#define MICROPY_HW_CAN2_NAME "YB" // CAN2 on RX,TX = Y5,Y6 = PB12,PB13 +#define MICROPY_HW_CAN1_NAME "YA" +#define MICROPY_HW_CAN1_TX (pin_B9) // Y4 +#define MICROPY_HW_CAN1_RX (pin_B8) // Y3 +#define MICROPY_HW_CAN2_NAME "YB" +#define MICROPY_HW_CAN2_TX (pin_B13) // Y6 +#define MICROPY_HW_CAN2_RX (pin_B12) // Y5 // 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/ports/stm32/boards/STM32F429DISC/mpconfigboard.h b/ports/stm32/boards/STM32F429DISC/mpconfigboard.h index 01713f7f8a..be25d2e772 100644 --- a/ports/stm32/boards/STM32F429DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F429DISC/mpconfigboard.h @@ -5,7 +5,6 @@ #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_CAN (1) #define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz @@ -50,6 +49,12 @@ //#define MICROPY_HW_SPI6_MISO (pin_G12) //#define MICROPY_HW_SPI6_MOSI (pin_G14) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_A0) #define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) diff --git a/ports/stm32/boards/STM32F439/mpconfigboard.h b/ports/stm32/boards/STM32F439/mpconfigboard.h index 66bfcf2ecc..4ac5b32138 100644 --- a/ports/stm32/boards/STM32F439/mpconfigboard.h +++ b/ports/stm32/boards/STM32F439/mpconfigboard.h @@ -6,7 +6,6 @@ #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (1) #define MICROPY_HW_ENABLE_USB (1) // SD card detect switch @@ -75,6 +74,12 @@ //#define MICROPY_HW_SPI6_MISO (pin_G12) //#define MICROPY_HW_SPI6_MOSI (pin_G14) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_A0) #define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) diff --git a/ports/stm32/boards/STM32F4DISC/mpconfigboard.h b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h index 66ef830bf4..3e4c8261cc 100644 --- a/ports/stm32/boards/STM32F4DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h @@ -6,7 +6,6 @@ #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (1) #define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz @@ -60,6 +59,12 @@ #define MICROPY_HW_SPI2_MISO (pin_B14) #define MICROPY_HW_SPI2_MOSI (pin_B15) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_A0) #define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h index 95201501be..8b29e5773e 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h @@ -10,7 +10,6 @@ #define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_CAN (1) #define MICROPY_HW_ENABLE_USB (1) // HSE is 25MHz @@ -44,6 +43,12 @@ #define MICROPY_HW_SPI2_MISO (pin_B14) #define MICROPY_HW_SPI2_MOSI (pin_B15) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_A0) #define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) diff --git a/ports/stm32/boards/STM32F769DISC/pins.csv b/ports/stm32/boards/STM32F769DISC/pins.csv index dcc2df2089..e68ed95366 100644 --- a/ports/stm32/boards/STM32F769DISC/pins.csv +++ b/ports/stm32/boards/STM32F769DISC/pins.csv @@ -55,3 +55,5 @@ UART1_TX,PA9 UART1_RX,PA10 UART5_TX,PC12 UART5_RX,PD2 +CAN2_TX,PB13 +CAN2_RX,PB12 diff --git a/ports/stm32/boards/STM32F7DISC/mpconfigboard.h b/ports/stm32/boards/STM32F7DISC/mpconfigboard.h index 9fce1deebc..7b506a3056 100644 --- a/ports/stm32/boards/STM32F7DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F7DISC/mpconfigboard.h @@ -6,7 +6,6 @@ #define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_CAN (1) #define MICROPY_HW_ENABLE_USB (1) #define MICROPY_BOARD_EARLY_INIT STM32F7DISC_board_early_init @@ -50,6 +49,12 @@ void STM32F7DISC_board_early_init(void); #define MICROPY_HW_SPI2_MISO (pin_B14) #define MICROPY_HW_SPI2_MOSI (pin_B15) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_I11) #define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) diff --git a/ports/stm32/boards/STM32F7DISC/pins.csv b/ports/stm32/boards/STM32F7DISC/pins.csv index 1aa8a9b3a1..8b49003f7c 100644 --- a/ports/stm32/boards/STM32F7DISC/pins.csv +++ b/ports/stm32/boards/STM32F7DISC/pins.csv @@ -51,3 +51,5 @@ USB_DM,PA11 USB_DP,PA12 VCP_TX,PA9 VCP_RX,PB7 +CAN_TX,PB13 +CAN_RX,PB12 diff --git a/ports/stm32/boards/STM32L476DISC/mpconfigboard.h b/ports/stm32/boards/STM32L476DISC/mpconfigboard.h index 3d8b74e4ab..a35dee1182 100644 --- a/ports/stm32/boards/STM32L476DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32L476DISC/mpconfigboard.h @@ -9,7 +9,6 @@ void STM32L476DISC_board_early_init(void); #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_CAN (1) #define MICROPY_HW_ENABLE_USB (1) // use external SPI flash for storage @@ -58,6 +57,10 @@ extern struct _spi_bdev_t spi_bdev; #define MICROPY_HW_SPI2_MISO (pin_D3) #define MICROPY_HW_SPI2_MOSI (pin_D4) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) + // Joystick is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_A0) #define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) diff --git a/ports/stm32/boards/make-pins.py b/ports/stm32/boards/make-pins.py index c9f6516f1c..70f154fde0 100755 --- a/ports/stm32/boards/make-pins.py +++ b/ports/stm32/boards/make-pins.py @@ -16,6 +16,7 @@ SUPPORTED_FN = { 'UART' : ['RX', 'TX', 'CTS', 'RTS'], 'SPI' : ['NSS', 'SCK', 'MISO', 'MOSI'], 'SDMMC' : ['CK', 'CMD', 'D0', 'D1', 'D2', 'D3'], + 'CAN' : ['TX', 'RX'], } CONDITIONAL_VAR = { @@ -25,6 +26,7 @@ CONDITIONAL_VAR = { 'UART' : 'MICROPY_HW_UART{num}_TX', 'USART' : 'MICROPY_HW_UART{num}_TX', 'SDMMC' : 'MICROPY_HW_SDMMC{num}_CK', + 'CAN' : 'MICROPY_HW_CAN{num}_TX', } def parse_port_pin(name_str): diff --git a/ports/stm32/can.c b/ports/stm32/can.c index bc4f1092cf..ae8e8e27ea 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -104,31 +104,26 @@ STATIC uint8_t can2_start_bank = 14; // assumes Init parameters have been set up correctly STATIC bool can_init(pyb_can_obj_t *can_obj) { CAN_TypeDef *CANx = NULL; - - uint32_t GPIO_Pin = 0; - uint8_t GPIO_AF_CANx = 0; - GPIO_TypeDef* GPIO_Port = NULL; uint32_t sce_irq = 0; + const pin_obj_t *pins[2]; switch (can_obj->can_id) { - // CAN1 is on RX,TX = Y3,Y4 = PB9,PB9 + #if defined(MICROPY_HW_CAN1_TX) case PYB_CAN_1: CANx = CAN1; - GPIO_AF_CANx = GPIO_AF9_CAN1; - GPIO_Port = GPIOB; - GPIO_Pin = GPIO_PIN_8 | GPIO_PIN_9; sce_irq = CAN1_SCE_IRQn; + pins[0] = MICROPY_HW_CAN1_TX; + pins[1] = MICROPY_HW_CAN1_RX; __CAN1_CLK_ENABLE(); break; + #endif - #if defined(CAN2) - // CAN2 is on RX,TX = Y5,Y6 = PB12,PB13 + #if defined(MICROPY_HW_CAN2_TX) case PYB_CAN_2: CANx = CAN2; - GPIO_AF_CANx = GPIO_AF9_CAN2; - GPIO_Port = GPIOB; - GPIO_Pin = GPIO_PIN_12 | GPIO_PIN_13; sce_irq = CAN2_SCE_IRQn; + pins[0] = MICROPY_HW_CAN2_TX; + pins[1] = MICROPY_HW_CAN2_RX; __CAN1_CLK_ENABLE(); // CAN2 is a "slave" and needs CAN1 enabled as well __CAN2_CLK_ENABLE(); break; @@ -139,13 +134,13 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { } // init GPIO - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.Pin = GPIO_Pin; - GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; - GPIO_InitStructure.Pull = GPIO_PULLUP; - GPIO_InitStructure.Alternate = GPIO_AF_CANx; - HAL_GPIO_Init(GPIO_Port, &GPIO_InitStructure); + uint32_t mode = MP_HAL_PIN_MODE_ALT; + uint32_t pull = MP_HAL_PIN_PULL_UP; + for (int i = 0; i < 2; i++) { + if (!mp_hal_pin_config_alt(pins[i], mode, pull, AF_FN_CAN, can_obj->can_id)) { + return false; + } + } // init CANx can_obj->can.Instance = CANx; diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index d4b812331d..5f3ac164d0 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -57,11 +57,6 @@ #define MICROPY_HW_ENABLE_DAC (0) #endif -// Whether to enable the CAN peripheral, exposed as pyb.CAN -#ifndef MICROPY_HW_ENABLE_CAN -#define MICROPY_HW_ENABLE_CAN (0) -#endif - // Whether to enable USB support #ifndef MICROPY_HW_ENABLE_USB #define MICROPY_HW_ENABLE_USB (0) @@ -156,6 +151,13 @@ #define MICROPY_HW_ENABLE_HW_I2C (0) #endif +// Enable CAN if there are any peripherals defined +#if defined(MICROPY_HW_CAN1_TX) || defined(MICROPY_HW_CAN2_TX) +#define MICROPY_HW_ENABLE_CAN (1) +#else +#define MICROPY_HW_ENABLE_CAN (0) +#endif + // Pin definition header file #define MICROPY_PIN_DEFS_PORT_H "pin_defs_stm32.h" diff --git a/ports/stm32/pin_defs_stm32.h b/ports/stm32/pin_defs_stm32.h index feaf56ae97..5c5c6be697 100644 --- a/ports/stm32/pin_defs_stm32.h +++ b/ports/stm32/pin_defs_stm32.h @@ -49,6 +49,7 @@ enum { AF_FN_SPI, AF_FN_I2S, AF_FN_SDMMC, + AF_FN_CAN, }; enum { @@ -93,6 +94,9 @@ enum { AF_PIN_TYPE_SDMMC_D1, AF_PIN_TYPE_SDMMC_D2, AF_PIN_TYPE_SDMMC_D3, + + AF_PIN_TYPE_CAN_TX = 0, + AF_PIN_TYPE_CAN_RX, }; // The HAL uses a slightly different naming than we chose, so we provide diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 987ace69a7..03321a1a93 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -736,7 +736,7 @@ void UART8_IRQHandler(void) { } #endif -#if MICROPY_HW_ENABLE_CAN +#if defined(MICROPY_HW_CAN1_TX) void CAN1_RX0_IRQHandler(void) { IRQ_ENTER(CAN1_RX0_IRQn); can_rx_irq_handler(PYB_CAN_1, CAN_FIFO0); @@ -754,7 +754,9 @@ void CAN1_SCE_IRQHandler(void) { can_sce_irq_handler(PYB_CAN_1); IRQ_EXIT(CAN1_SCE_IRQn); } +#endif +#if defined(MICROPY_HW_CAN2_TX) void CAN2_RX0_IRQHandler(void) { IRQ_ENTER(CAN2_RX0_IRQn); can_rx_irq_handler(PYB_CAN_2, CAN_FIFO0); @@ -772,7 +774,7 @@ void CAN2_SCE_IRQHandler(void) { can_sce_irq_handler(PYB_CAN_2); IRQ_EXIT(CAN2_SCE_IRQn); } -#endif // MICROPY_HW_ENABLE_CAN +#endif #if defined(MICROPY_HW_I2C1_SCL) void I2C1_EV_IRQHandler(void) { From 68b70fac5cce7bfa3416dd04440e3a7c1979ffc5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 11 Apr 2018 16:37:45 +1000 Subject: [PATCH 545/828] stm32/stm32_it: Add IRQ handler for I2C4. --- ports/stm32/stm32_it.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 03321a1a93..04abfd211e 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -817,3 +817,17 @@ void I2C3_ER_IRQHandler(void) { IRQ_EXIT(I2C3_ER_IRQn); } #endif // defined(MICROPY_HW_I2C3_SCL) + +#if defined(MICROPY_HW_I2C4_SCL) +void I2C4_EV_IRQHandler(void) { + IRQ_ENTER(I2C4_EV_IRQn); + i2c_ev_irq_handler(4); + IRQ_EXIT(I2C4_EV_IRQn); +} + +void I2C4_ER_IRQHandler(void) { + IRQ_ENTER(I2C4_ER_IRQn); + i2c_er_irq_handler(4); + IRQ_EXIT(I2C4_ER_IRQn); +} +#endif // defined(MICROPY_HW_I2C4_SCL) From cf9fc7346d91d729e5f6248d4bbbe5cb199cc772 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 11 Apr 2018 16:46:47 +1000 Subject: [PATCH 546/828] stm32: Allow a board to configure the HSE in bypass mode. To use HSE bypass mode the board should define: #define MICROPY_HW_CLK_USE_BYPASS (1) If this is not defined, or is defined to 0, then HSE oscillator mode is used. --- ports/stm32/modmachine.c | 4 ++-- ports/stm32/mpconfigboard_common.h | 7 +++++++ ports/stm32/stm32_it.c | 2 +- ports/stm32/system_stm32.c | 2 +- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index 02a6f2a4b9..6b7849bb9b 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -377,7 +377,7 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { // even if we don't use the PLL for the system clock, we still need it for USB, RNG and SDIO RCC_OscInitTypeDef RCC_OscInitStruct; RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; - RCC_OscInitStruct.HSEState = RCC_HSE_ON; + RCC_OscInitStruct.HSEState = MICROPY_HW_CLK_HSE_STATE; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = m; @@ -500,7 +500,7 @@ STATIC mp_obj_t machine_sleep(void) { // reconfigure the system clock after waking up // enable HSE - __HAL_RCC_HSE_CONFIG(RCC_HSE_ON); + __HAL_RCC_HSE_CONFIG(MICROPY_HW_CLK_HSE_STATE); while (!__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY)) { } diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 5f3ac164d0..857457fdb7 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -136,6 +136,13 @@ #error Unsupported MCU series #endif +// Configure HSE for bypass or oscillator +#if MICROPY_HW_CLK_USE_BYPASS +#define MICROPY_HW_CLK_HSE_STATE (RCC_HSE_BYPASS) +#else +#define MICROPY_HW_CLK_HSE_STATE (RCC_HSE_ON) +#endif + #if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE // Provide block device macros if internal flash storage is enabled #define MICROPY_HW_BDEV_IOCTL flash_bdev_ioctl diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 04abfd211e..db812958fb 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -369,7 +369,7 @@ STATIC void OTG_CMD_WKUP_Handler(PCD_HandleTypeDef *pcd_handle) { /* Configures system clock after wake-up from STOP: enable HSE, PLL and select PLL as system clock source (HSE and PLL are disabled in STOP mode) */ - __HAL_RCC_HSE_CONFIG(RCC_HSE_ON); + __HAL_RCC_HSE_CONFIG(MICROPY_HW_CLK_HSE_STATE); /* Wait till HSE is ready */ while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET) diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c index 251902259e..70bbb2a8bd 100644 --- a/ports/stm32/system_stm32.c +++ b/ports/stm32/system_stm32.c @@ -404,7 +404,7 @@ void SystemClock_Config(void) /* Enable HSE Oscillator and activate PLL with HSE as source */ #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; - RCC_OscInitStruct.HSEState = RCC_HSE_ON; + RCC_OscInitStruct.HSEState = MICROPY_HW_CLK_HSE_STATE; RCC_OscInitStruct.HSIState = RCC_HSI_OFF; #if defined(STM32H7) RCC_OscInitStruct.CSIState = RCC_CSI_OFF; From 3d5d76fb7384cd6c0bcd62f6a6799261b73f786d Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 11 Apr 2018 16:52:22 +1000 Subject: [PATCH 547/828] stm32/main: Allow a board to configure the label of the flash FS. To change the default label a board should define: #define MICROPY_HW_FLASH_FS_LABEL "label" --- ports/stm32/main.c | 2 +- ports/stm32/mpconfigboard_common.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 120ab5b670..4d0e7434be 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -192,7 +192,7 @@ MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { } // set label - f_setlabel(&vfs_fat->fatfs, "pybflash"); + f_setlabel(&vfs_fat->fatfs, MICROPY_HW_FLASH_FS_LABEL); // create empty main.py FIL fp; diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 857457fdb7..97c21d0227 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -92,6 +92,11 @@ #define MICROPY_HW_HAS_LCD (0) #endif +// The volume label used when creating the flash filesystem +#ifndef MICROPY_HW_FLASH_FS_LABEL +#define MICROPY_HW_FLASH_FS_LABEL "pybflash" +#endif + /*****************************************************************************/ // General configuration From d12483d93662d0aa1a421f4f8348c7e960c25183 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 11 Apr 2018 17:12:13 +1000 Subject: [PATCH 548/828] tests/pyb: Add test for pyb.ADCAll class. --- tests/pyb/adcall.py | 31 +++++++++++++++++++++++++++++++ tests/pyb/adcall.py.exp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 tests/pyb/adcall.py create mode 100644 tests/pyb/adcall.py.exp diff --git a/tests/pyb/adcall.py b/tests/pyb/adcall.py new file mode 100644 index 0000000000..afc3033ea8 --- /dev/null +++ b/tests/pyb/adcall.py @@ -0,0 +1,31 @@ +from pyb import Pin, ADCAll + +pins = [Pin.cpu.A0, Pin.cpu.A1, Pin.cpu.A2, Pin.cpu.A3] + +# set pins to IN mode, init ADCAll, then check pins are ANALOG +for p in pins: + p.init(p.IN) +adc = pyb.ADCAll(12) +for p in pins: + print(p) + +# set pins to IN mode, init ADCAll with mask, then check some pins are ANALOG +for p in pins: + p.init(p.IN) +adc = pyb.ADCAll(12, 0x70003) +for p in pins: + print(p) + +# init all pins to ANALOG +adc = pyb.ADCAll(12) +print(adc) + +# read all channels +for c in range(19): + print(type(adc.read_channel(c))) + +# call special reading functions +print(0 < adc.read_core_temp() < 100) +print(0 < adc.read_core_vbat() < 4) +print(0 < adc.read_core_vref() < 2) +print(0 < adc.read_vref() < 4) diff --git a/tests/pyb/adcall.py.exp b/tests/pyb/adcall.py.exp new file mode 100644 index 0000000000..5a85ba770e --- /dev/null +++ b/tests/pyb/adcall.py.exp @@ -0,0 +1,32 @@ +Pin(Pin.cpu.A0, mode=Pin.ANALOG) +Pin(Pin.cpu.A1, mode=Pin.ANALOG) +Pin(Pin.cpu.A2, mode=Pin.ANALOG) +Pin(Pin.cpu.A3, mode=Pin.ANALOG) +Pin(Pin.cpu.A0, mode=Pin.ANALOG) +Pin(Pin.cpu.A1, mode=Pin.ANALOG) +Pin(Pin.cpu.A2, mode=Pin.IN) +Pin(Pin.cpu.A3, mode=Pin.IN) + + + + + + + + + + + + + + + + + + + + +True +True +True +True From 06006459447c8e7eaa031058a83f54bb06891bcb Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Wed, 11 Apr 2018 09:14:05 +0100 Subject: [PATCH 549/828] docs/library/pyb.ADC: Remove outdated ADCAll code example. --- docs/library/pyb.ADC.rst | 43 +++------------------------------------- 1 file changed, 3 insertions(+), 40 deletions(-) diff --git a/docs/library/pyb.ADC.rst b/docs/library/pyb.ADC.rst index 1256c6a3c1..679ba2f5ac 100644 --- a/docs/library/pyb.ADC.rst +++ b/docs/library/pyb.ADC.rst @@ -170,44 +170,7 @@ The ADCAll Object The default value is 0xffffffff which means all analog inputs are active. If just the internal channels (16..18) are required, the mask value should be 0x70000. - It is possible to access channle 16..18 values without incurring the side effects of ``ADCAll``:: - - def adcread(chan): # 16 temp 17 vbat 18 vref - assert chan >= 16 and chan <= 18, 'Invalid ADC channel' - start = pyb.millis() - timeout = 100 - stm.mem32[stm.RCC + stm.RCC_APB2ENR] |= 0x100 # enable ADC1 clock.0x4100 - stm.mem32[stm.ADC1 + stm.ADC_CR2] = 1 # Turn on ADC - stm.mem32[stm.ADC1 + stm.ADC_CR1] = 0 # 12 bit - if chan == 17: - stm.mem32[stm.ADC1 + stm.ADC_SMPR1] = 0x200000 # 15 cycles - stm.mem32[stm.ADC + 4] = 1 << 23 - elif chan == 18: - stm.mem32[stm.ADC1 + stm.ADC_SMPR1] = 0x1000000 - stm.mem32[stm.ADC + 4] = 0xc00000 - else: - stm.mem32[stm.ADC1 + stm.ADC_SMPR1] = 0x40000 - stm.mem32[stm.ADC + 4] = 1 << 23 - stm.mem32[stm.ADC1 + stm.ADC_SQR3] = chan - stm.mem32[stm.ADC1 + stm.ADC_CR2] = 1 | (1 << 30) | (1 << 10) # start conversion - while not stm.mem32[stm.ADC1 + stm.ADC_SR] & 2: # wait for EOC - if pyb.elapsed_millis(start) > timeout: - raise OSError('ADC timout') - data = stm.mem32[stm.ADC1 + stm.ADC_DR] # clear down EOC - stm.mem32[stm.ADC1 + stm.ADC_CR2] = 0 # Turn off ADC - return data + Example:: - def v33(): - return 4096 * 1.21 / adcread(17) - - def vbat(): - return 1.21 * 2 * adcread(18) / adcread(17) # 2:1 divider on Vbat channel - - def vref(): - return 3.3 * adcread(17) / 4096 - - def temperature(): - return 25 + 400 * (3.3 * adcread(16) / 4096 - 0.76) - - Note that this example is only valid for the F405 MCU and all values are not corrected by Vref and - factory calibration data. + adcall = pyb.ADCAll(12, 0x70000) # 12 bit resolution, internal channels + temp = adcall.read_core_temp() From c24b0a7f2b7c0c30ef5fde62342eab7c0931f400 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 20 Apr 2018 15:54:09 +1000 Subject: [PATCH 550/828] docs/library/pyb.ADC: Fix typo of "prarmeter". --- docs/library/pyb.ADC.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/library/pyb.ADC.rst b/docs/library/pyb.ADC.rst index 679ba2f5ac..05aaa50150 100644 --- a/docs/library/pyb.ADC.rst +++ b/docs/library/pyb.ADC.rst @@ -165,7 +165,7 @@ The ADCAll Object Other analog input channels (0..15) will return unscaled integer values according to the selected precision. - To avoid unwanted activation of analog inputs (channel 0..15) a second prarmeter can be specified. + To avoid unwanted activation of analog inputs (channel 0..15) a second parameter can be specified. This parameter is a binary pattern where each requested analog input has the corresponding bit set. The default value is 0xffffffff which means all analog inputs are active. If just the internal channels (16..18) are required, the mask value should be 0x70000. From 9adfd1464495a24c6359ced2db1bd842752f7a79 Mon Sep 17 00:00:00 2001 From: "Peter D. Gray" Date: Fri, 13 Apr 2018 09:26:58 -0400 Subject: [PATCH 551/828] stm32/sdcard: Implement BP_IOCTL_SEC_COUNT to get size of SD card. --- ports/stm32/sdcard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index 9244be5d4f..4eb9fce6cd 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -539,7 +539,7 @@ STATIC mp_obj_t pyb_sdcard_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in return MP_OBJ_NEW_SMALL_INT(0); // success case BP_IOCTL_SEC_COUNT: - return MP_OBJ_NEW_SMALL_INT(0); // TODO + return MP_OBJ_NEW_SMALL_INT(sdcard_get_capacity_in_bytes() / SDCARD_BLOCK_SIZE); case BP_IOCTL_SEC_SIZE: return MP_OBJ_NEW_SMALL_INT(SDCARD_BLOCK_SIZE); From b5ee3b2f21611b5a420e2ffb4cf2a239806dc763 Mon Sep 17 00:00:00 2001 From: Shanee Vanstone Date: Tue, 17 Apr 2018 13:59:11 +0100 Subject: [PATCH 552/828] esp32/README.md: Fix typo readme. --- ports/esp32/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp32/README.md b/ports/esp32/README.md index ffd651c458..16855505fd 100644 --- a/ports/esp32/README.md +++ b/ports/esp32/README.md @@ -64,7 +64,7 @@ the following commands on (at least) Linux: $ export PATH=$PATH:$HOME/esp/crosstool-NG/builds/xtensa-esp32-elf/bin -You cam put this command in your `.profile` or `.bash_login`. +You can put this command in your `.profile` or `.bash_login`. You then need to set the `ESPIDF` environment/makefile variable to point to the root of the ESP-IDF repository. You can set the variable in your PATH, From f7be5f9bfa61a07a8256aaae8f22d151f6b8ad81 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 23 Apr 2018 16:11:27 +1000 Subject: [PATCH 553/828] tools/upip: Upgrade upip to 1.2.4. Uses new pypi.org URL, and now creates a socket with the address parameters returned by getaddrinfo(). --- tools/bootstrap_upip.sh | 2 +- tools/upip.py | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/tools/bootstrap_upip.sh b/tools/bootstrap_upip.sh index 667d0845a4..2891775d7d 100755 --- a/tools/bootstrap_upip.sh +++ b/tools/bootstrap_upip.sh @@ -17,7 +17,7 @@ fi # Remove any stale old version rm -rf micropython-upip-* -wget -nd -r -l1 https://pypi.python.org/pypi/micropython-upip/ --accept-regex ".*pypi.python.org/packages/source/.*.gz" --reject=html +wget -nd -rH -l1 -D files.pythonhosted.org https://pypi.org/project/micropython-upip/ --reject=html tar xfz micropython-upip-*.tar.gz tmpd="$PWD" diff --git a/tools/upip.py b/tools/upip.py index 411da49e8c..a400c31743 100644 --- a/tools/upip.py +++ b/tools/upip.py @@ -1,3 +1,10 @@ +# +# upip - Package manager for MicroPython +# +# Copyright (c) 2015-2018 Paul Sokolovsky +# +# Licensed under the MIT license. +# import sys import gc import uos as os @@ -110,16 +117,16 @@ def url_open(url): proto, _, host, urlpath = url.split('/', 3) try: - ai = usocket.getaddrinfo(host, 443) + ai = usocket.getaddrinfo(host, 443, 0, usocket.SOCK_STREAM) except OSError as e: fatal("Unable to resolve %s (no Internet?)" % host, e) #print("Address infos:", ai) - addr = ai[0][4] + ai = ai[0] - s = usocket.socket(ai[0][0]) + s = usocket.socket(ai[0], ai[1], ai[2]) try: #print("Connect address:", addr) - s.connect(addr) + s.connect(ai[-1]) if proto == "https:": s = ussl.wrap_socket(s, server_hostname=host) @@ -149,7 +156,7 @@ def url_open(url): def get_pkg_metadata(name): - f = url_open("https://pypi.python.org/pypi/%s/json" % name) + f = url_open("https://pypi.org/pypi/%s/json" % name) try: return json.load(f) finally: From bdff68db9c1f7e35d0600841647cffac4b1d9ef0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 23 Apr 2018 16:38:20 +1000 Subject: [PATCH 554/828] extmod/modlwip: Check if getaddrinfo() constraints are supported or not. In particular don't issue a warning if the passed-in constraints are actually supported because they are the default values. --- extmod/modlwip.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 9810089da3..b23f53961a 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -1292,14 +1292,33 @@ STATIC void lwip_getaddrinfo_cb(const char *name, ip_addr_t *ipaddr, void *arg) // lwip.getaddrinfo STATIC mp_obj_t lwip_getaddrinfo(size_t n_args, const mp_obj_t *args) { - if (n_args > 2) { - mp_warning("getaddrinfo constraints not supported"); - } - mp_obj_t host_in = args[0], port_in = args[1]; const char *host = mp_obj_str_get_str(host_in); mp_int_t port = mp_obj_get_int(port_in); + // If constraints were passed then check they are compatible with the supported params + if (n_args > 2) { + mp_int_t family = mp_obj_get_int(args[2]); + mp_int_t type = 0; + mp_int_t proto = 0; + mp_int_t flags = 0; + if (n_args > 3) { + type = mp_obj_get_int(args[3]); + if (n_args > 4) { + proto = mp_obj_get_int(args[4]); + if (n_args > 5) { + flags = mp_obj_get_int(args[5]); + } + } + } + if (!((family == 0 || family == MOD_NETWORK_AF_INET) + && (type == 0 || type == MOD_NETWORK_SOCK_STREAM) + && proto == 0 + && flags == 0)) { + mp_warning("unsupported getaddrinfo constraints"); + } + } + getaddrinfo_state_t state; state.status = 0; From 70a6a15f8c5f8fba9b9fd9b57502e2fd815c6e73 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Sat, 14 Apr 2018 00:11:07 +0200 Subject: [PATCH 555/828] stm32/rng: Set RNG clock source for STM32H7. --- ports/stm32/rng.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ports/stm32/rng.c b/ports/stm32/rng.c index 85dcc14109..e70eafae71 100644 --- a/ports/stm32/rng.c +++ b/ports/stm32/rng.c @@ -33,6 +33,11 @@ uint32_t rng_get(void) { // Enable the RNG peripheral if it's not already enabled if (!(RNG->CR & RNG_CR_RNGEN)) { + #if defined(STM32H7) + // Set RNG Clock source + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL1_DIVQ); + __HAL_RCC_RNG_CONFIG(RCC_RNGCLKSOURCE_PLL); + #endif __HAL_RCC_RNG_CLK_ENABLE(); RNG->CR |= RNG_CR_RNGEN; } From d870a4e835cf1474db7f58b3df78c11e3e7e34bc Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Sat, 14 Apr 2018 00:11:46 +0200 Subject: [PATCH 556/828] stm32/boards/NUCLEO_H743ZI: Enable RNG for this board. --- ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h index d2a34795e7..d23c5bab04 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h @@ -2,6 +2,7 @@ #define MICROPY_HW_MCU_NAME "STM32H743" #define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_ADC (0) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_USB (1) From 513e5372155bed86285aa38ce828390c65d52761 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 23 Apr 2018 17:06:40 +1000 Subject: [PATCH 557/828] stm32/uart: Allow ctrl-C to issue keyboard intr when REPL is over UART. --- ports/stm32/uart.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index a8b5d7dcae..0621dc725a 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -32,8 +32,10 @@ #include "py/stream.h" #include "py/mperrno.h" #include "py/mphal.h" +#include "lib/utils/interrupt_char.h" #include "uart.h" #include "irq.h" +#include "pendsv.h" /// \moduleref pyb /// \class UART - duplex serial communication bus @@ -506,6 +508,11 @@ void uart_irq_handler(mp_uint_t uart_id) { int data = self->uart.Instance->DR; // clears UART_FLAG_RXNE #endif data &= self->char_mask; + // Handle interrupt coming in on a UART REPL + if (data == mp_interrupt_char && self == MP_STATE_PORT(pyb_stdio_uart)) { + pendsv_kbd_intr(); + return; + } if (self->char_width == CHAR_WIDTH_9BIT) { ((uint16_t*)self->read_buf)[self->read_buf_head] = data; } else { From a60efa8202d84a2d3efe522009d700dac289538e Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 23 Apr 2018 20:44:30 +1000 Subject: [PATCH 558/828] stm32/uart: Allow ctrl-C to work with UARTs put on REPL via os.dupterm. --- ports/stm32/main.c | 1 + ports/stm32/modpyb.c | 6 +++++- ports/stm32/moduos.c | 14 +++++++++++++- ports/stm32/uart.c | 8 +++++++- ports/stm32/uart.h | 1 + 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 4d0e7434be..eefe47490c 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -543,6 +543,7 @@ soft_reset: MP_OBJ_NEW_SMALL_INT(MICROPY_HW_UART_REPL_BAUD), }; MP_STATE_PORT(pyb_stdio_uart) = pyb_uart_type.make_new((mp_obj_t)&pyb_uart_type, MP_ARRAY_SIZE(args), 0, args); + uart_attach_to_repl(MP_STATE_PORT(pyb_stdio_uart), true); } #else MP_STATE_PORT(pyb_stdio_uart) = NULL; diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c index c7f2844a4d..59c6ba67cb 100644 --- a/ports/stm32/modpyb.c +++ b/ports/stm32/modpyb.c @@ -116,9 +116,13 @@ STATIC mp_obj_t pyb_repl_uart(size_t n_args, const mp_obj_t *args) { } } else { if (args[0] == mp_const_none) { - MP_STATE_PORT(pyb_stdio_uart) = NULL; + if (MP_STATE_PORT(pyb_stdio_uart) != NULL) { + uart_attach_to_repl(MP_STATE_PORT(pyb_stdio_uart), false); + MP_STATE_PORT(pyb_stdio_uart) = NULL; + } } else if (mp_obj_get_type(args[0]) == &pyb_uart_type) { MP_STATE_PORT(pyb_stdio_uart) = args[0]; + uart_attach_to_repl(MP_STATE_PORT(pyb_stdio_uart), true); } else { mp_raise_ValueError("need a UART object"); } diff --git a/ports/stm32/moduos.c b/ports/stm32/moduos.c index f6e1483d35..5728f9c61c 100644 --- a/ports/stm32/moduos.c +++ b/ports/stm32/moduos.c @@ -106,6 +106,18 @@ STATIC mp_obj_t os_urandom(mp_obj_t num) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); #endif +STATIC mp_obj_t uos_dupterm(size_t n_args, const mp_obj_t *args) { + mp_obj_t prev_obj = mp_uos_dupterm_obj.fun.var(n_args, args); + if (mp_obj_get_type(prev_obj) == &pyb_uart_type) { + uart_attach_to_repl(MP_OBJ_TO_PTR(prev_obj), false); + } + if (mp_obj_get_type(args[0]) == &pyb_uart_type) { + uart_attach_to_repl(MP_OBJ_TO_PTR(args[0]), true); + } + return prev_obj; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(uos_dupterm_obj, 1, 2, uos_dupterm); + STATIC const mp_rom_map_elem_t os_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, @@ -133,7 +145,7 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = { #endif // these are MicroPython extensions - { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) }, + { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&uos_dupterm_obj) }, { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) }, { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index 0621dc725a..677606940e 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -81,6 +81,7 @@ struct _pyb_uart_obj_t { IRQn_Type irqn; pyb_uart_t uart_id : 8; bool is_enabled : 1; + bool attached_to_repl; // whether the UART is attached to REPL byte char_width; // 0 for 7,8 bit chars, 1 for 9 bit chars uint16_t char_mask; // 0x7f for 7 bit, 0xff for 8 bit, 0x1ff for 9 bit uint16_t timeout; // timeout waiting for first char @@ -320,10 +321,15 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { HAL_UART_Init(&uart_obj->uart); uart_obj->is_enabled = true; + uart_obj->attached_to_repl = false; return true; } +void uart_attach_to_repl(pyb_uart_obj_t *self, bool attached) { + self->attached_to_repl = attached; +} + /* obsolete and unused bool uart_init(pyb_uart_obj_t *uart_obj, uint32_t baudrate) { UART_HandleTypeDef *uh = &uart_obj->uart; @@ -509,7 +515,7 @@ void uart_irq_handler(mp_uint_t uart_id) { #endif data &= self->char_mask; // Handle interrupt coming in on a UART REPL - if (data == mp_interrupt_char && self == MP_STATE_PORT(pyb_stdio_uart)) { + if (self->attached_to_repl && data == mp_interrupt_char) { pendsv_kbd_intr(); return; } diff --git a/ports/stm32/uart.h b/ports/stm32/uart.h index d06508e8ed..4ab18ff225 100644 --- a/ports/stm32/uart.h +++ b/ports/stm32/uart.h @@ -45,6 +45,7 @@ void uart_init0(void); void uart_deinit(void); void uart_irq_handler(mp_uint_t uart_id); +void uart_attach_to_repl(pyb_uart_obj_t *self, bool attached); mp_uint_t uart_rx_any(pyb_uart_obj_t *uart_obj); int uart_rx_char(pyb_uart_obj_t *uart_obj); void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len); From 8a949ba599df740e6d0c9154619c6f83f2949924 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 24 Apr 2018 12:01:49 +1000 Subject: [PATCH 559/828] stm32: Introduce MICROPY_PY_STM config to include or not the stm module. By default the stm module is included in the build, but a board can now define MICROPY_PY_STM to 0 to not include this module. This reduces the firmware by about 7k. --- ports/stm32/make-stmconst.py | 2 ++ ports/stm32/modstm.c | 7 ++++++- ports/stm32/mpconfigboard_common.h | 5 +++++ ports/stm32/mpconfigport.h | 10 ++++++++-- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/ports/stm32/make-stmconst.py b/ports/stm32/make-stmconst.py index 3a8e22b386..d509d00c1c 100644 --- a/ports/stm32/make-stmconst.py +++ b/ports/stm32/make-stmconst.py @@ -244,8 +244,10 @@ def main(): print("") with open(args.qstr_filename, 'wt') as qstr_file: + print('#if MICROPY_PY_STM', file=qstr_file) for qstr in sorted(needed_qstrs): print('Q({})'.format(qstr), file=qstr_file) + print('#endif // MICROPY_PY_STM', file=qstr_file) with open(args.mpz_filename, 'wt') as mpz_file: for mpz in sorted(needed_mpzs): diff --git a/ports/stm32/modstm.c b/ports/stm32/modstm.c index 2084c0aa0e..3fae3a57c4 100644 --- a/ports/stm32/modstm.c +++ b/ports/stm32/modstm.c @@ -30,9 +30,12 @@ #include "py/obj.h" #include "py/objint.h" #include "extmod/machine_mem.h" -#include "genhdr/modstm_mpz.h" #include "portmodules.h" +#if MICROPY_PY_STM + +#include "genhdr/modstm_mpz.h" + STATIC const mp_rom_map_elem_t stm_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_stm) }, @@ -49,3 +52,5 @@ const mp_obj_module_t stm_module = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&stm_module_globals, }; + +#endif // MICROPY_PY_STM diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 97c21d0227..2ed8609e74 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -32,6 +32,11 @@ /*****************************************************************************/ // Feature settings with defaults +// Whether to include the stm module, with peripheral register constants +#ifndef MICROPY_PY_STM +#define MICROPY_PY_STM (1) +#endif + // Whether to enable storage on the internal flash of the MCU #ifndef MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE #define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (1) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index a0a67e95f9..72744f04b1 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -186,6 +186,12 @@ extern const struct _mp_obj_module_t mp_module_usocket; extern const struct _mp_obj_module_t mp_module_network; extern const struct _mp_obj_module_t mp_module_onewire; +#if MICROPY_PY_STM +#define STM_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_stm), MP_ROM_PTR(&stm_module) }, +#else +#define STM_BUILTIN_MODULE +#endif + #if MICROPY_PY_USOCKET #define SOCKET_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_usocket) }, #define SOCKET_BUILTIN_MODULE_WEAK_LINKS { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_usocket) }, @@ -203,7 +209,7 @@ extern const struct _mp_obj_module_t mp_module_onewire; #define MICROPY_PORT_BUILTIN_MODULES \ { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&machine_module) }, \ { MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, \ - { MP_ROM_QSTR(MP_QSTR_stm), MP_ROM_PTR(&stm_module) }, \ + STM_BUILTIN_MODULE \ { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos) }, \ { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \ SOCKET_BUILTIN_MODULE \ @@ -233,7 +239,7 @@ extern const struct _mp_obj_module_t mp_module_onewire; { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&machine_module) }, \ { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module) }, \ { MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, \ - { MP_ROM_QSTR(MP_QSTR_stm), MP_ROM_PTR(&stm_module) }, \ + STM_BUILTIN_MODULE \ #define MP_STATE_PORT MP_STATE_VM From 8b91260169e03a530c956da2e64ab8d4fdf6f5f7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 24 Apr 2018 12:07:59 +1000 Subject: [PATCH 560/828] stm32/dac: Support MCUs that don't have TIM4/5 and use new HAL macro. --- ports/stm32/dac.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c index 04acfb8aa1..5423a2bff7 100644 --- a/ports/stm32/dac.c +++ b/ports/stm32/dac.c @@ -105,10 +105,14 @@ STATIC uint32_t TIMx_Config(mp_obj_t timer) { // work out the trigger channel (only certain ones are supported) if (tim->Instance == TIM2) { return DAC_TRIGGER_T2_TRGO; + #if defined(TIM4) } else if (tim->Instance == TIM4) { return DAC_TRIGGER_T4_TRGO; + #endif + #if defined(TIM5) } else if (tim->Instance == TIM5) { return DAC_TRIGGER_T5_TRGO; + #endif #if defined(TIM6) } else if (tim->Instance == TIM6) { return DAC_TRIGGER_T6_TRGO; @@ -176,7 +180,7 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp #endif // stop anything already going on - __DMA1_CLK_ENABLE(); + __HAL_RCC_DMA1_CLK_ENABLE(); DMA_HandleTypeDef DMA_Handle; /* Get currently configured dma */ dma_init_handle(&DMA_Handle, self->tx_dma_descr, (void*)NULL); @@ -420,7 +424,7 @@ mp_obj_t pyb_dac_write_timed(size_t n_args, const mp_obj_t *pos_args, mp_map_t * dac_trigger = TIMx_Config(args[1].u_obj); } - __DMA1_CLK_ENABLE(); + __HAL_RCC_DMA1_CLK_ENABLE(); DMA_HandleTypeDef DMA_Handle; /* Get currently configured dma */ From b73adcc3d90da7fd2a66b76161b661a603403506 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 24 Apr 2018 16:23:36 +1000 Subject: [PATCH 561/828] stm32: Rename i2c.c to pyb_i2c.c. i2c.c implements the legacy pyb.I2C class so rename the file to make this explicit, and also to make room for an improved I2C driver. --- ports/stm32/Makefile | 2 +- ports/stm32/{i2c.c => pyb_i2c.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename ports/stm32/{i2c.c => pyb_i2c.c} (100%) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 0e7f7f71af..4e185b7948 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -216,7 +216,7 @@ SRC_C = \ pin_named_pins.c \ bufhelper.c \ dma.c \ - i2c.c \ + pyb_i2c.c \ spi.c \ qspi.c \ uart.c \ diff --git a/ports/stm32/i2c.c b/ports/stm32/pyb_i2c.c similarity index 100% rename from ports/stm32/i2c.c rename to ports/stm32/pyb_i2c.c From 0c54d0c28824dca608364e5cb64d00f607dc1209 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 24 Apr 2018 17:32:16 +1000 Subject: [PATCH 562/828] stm32: Rename legacy pyb.I2C helper functions to start with pyb_i2c_. --- ports/stm32/accel.c | 2 +- ports/stm32/i2c.h | 6 +++--- ports/stm32/machine_i2c.c | 4 ++-- ports/stm32/pyb_i2c.c | 20 ++++++++++---------- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/ports/stm32/accel.c b/ports/stm32/accel.c index ec76727824..488391c703 100644 --- a/ports/stm32/accel.c +++ b/ports/stm32/accel.c @@ -70,7 +70,7 @@ STATIC void accel_start(void) { I2CHandle1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; I2CHandle1.Init.OwnAddress1 = PYB_I2C_MASTER_ADDRESS; I2CHandle1.Init.OwnAddress2 = 0xfe; // unused - i2c_init(&I2CHandle1); + pyb_i2c_init(&I2CHandle1); // turn off AVDD, wait 30ms, turn on AVDD, wait 30ms again mp_hal_pin_low(MICROPY_HW_MMA_AVDD_PIN); // turn off diff --git a/ports/stm32/i2c.h b/ports/stm32/i2c.h index 6d3ff2201f..bf43f27281 100644 --- a/ports/stm32/i2c.h +++ b/ports/stm32/i2c.h @@ -47,9 +47,9 @@ extern const mp_obj_type_t pyb_i2c_type; extern const pyb_i2c_obj_t pyb_i2c_obj[4]; void i2c_init0(void); -void i2c_init(I2C_HandleTypeDef *i2c); -void i2c_init_freq(const pyb_i2c_obj_t *self, mp_int_t freq); -uint32_t i2c_get_baudrate(I2C_HandleTypeDef *i2c); +void pyb_i2c_init(I2C_HandleTypeDef *i2c); +void pyb_i2c_init_freq(const pyb_i2c_obj_t *self, mp_int_t freq); +uint32_t pyb_i2c_get_baudrate(I2C_HandleTypeDef *i2c); void i2c_ev_irq_handler(mp_uint_t i2c_id); void i2c_er_irq_handler(mp_uint_t i2c_id); diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c index 8fc6c2a1ed..54e8425713 100644 --- a/ports/stm32/machine_i2c.c +++ b/ports/stm32/machine_i2c.c @@ -87,13 +87,13 @@ STATIC void machine_hard_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "I2C(%u, freq=%u, timeout=%u)", self - &machine_hard_i2c_obj[0] + 1, - i2c_get_baudrate(self->pyb->i2c), + pyb_i2c_get_baudrate(self->pyb->i2c), *self->timeout); } STATIC void machine_hard_i2c_init(const machine_hard_i2c_obj_t *self, uint32_t freq, uint32_t timeout) { *self->timeout = timeout; - i2c_init_freq(self->pyb, freq); + pyb_i2c_init_freq(self->pyb, freq); } // this function is based on STM code diff --git a/ports/stm32/pyb_i2c.c b/ports/stm32/pyb_i2c.c index 6c135b3a5a..1b77ea0bef 100644 --- a/ports/stm32/pyb_i2c.c +++ b/ports/stm32/pyb_i2c.c @@ -201,7 +201,7 @@ STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) { "Unsupported I2C baudrate: %lu", baudrate)); } -uint32_t i2c_get_baudrate(I2C_HandleTypeDef *i2c) { +uint32_t pyb_i2c_get_baudrate(I2C_HandleTypeDef *i2c) { for (int i = 0; i < NUM_BAUDRATE_TIMINGS; i++) { if (pyb_i2c_baudrate_timing[i].timing == i2c->Init.Timing) { return pyb_i2c_baudrate_timing[i].baudrate; @@ -220,7 +220,7 @@ STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) { init->DutyCycle = I2C_DUTYCYCLE_16_9; } -uint32_t i2c_get_baudrate(I2C_HandleTypeDef *i2c) { +uint32_t pyb_i2c_get_baudrate(I2C_HandleTypeDef *i2c) { uint32_t pfreq = i2c->Instance->CR2 & 0x3f; uint32_t ccr = i2c->Instance->CCR & 0xfff; if (i2c->Instance->CCR & 0x8000) { @@ -251,7 +251,7 @@ void i2c_init0(void) { #endif } -void i2c_init(I2C_HandleTypeDef *i2c) { +void pyb_i2c_init(I2C_HandleTypeDef *i2c) { int i2c_unit; const pin_obj_t *scl_pin; const pin_obj_t *sda_pin; @@ -372,7 +372,7 @@ void i2c_deinit(I2C_HandleTypeDef *i2c) { } } -void i2c_init_freq(const pyb_i2c_obj_t *self, mp_int_t freq) { +void pyb_i2c_init_freq(const pyb_i2c_obj_t *self, mp_int_t freq) { I2C_InitTypeDef *init = &self->i2c->Init; init->AddressingMode = I2C_ADDRESSINGMODE_7BIT; @@ -389,7 +389,7 @@ void i2c_init_freq(const pyb_i2c_obj_t *self, mp_int_t freq) { // init the I2C bus i2c_deinit(self->i2c); - i2c_init(self->i2c); + pyb_i2c_init(self->i2c); } STATIC void i2c_reset_after_error(I2C_HandleTypeDef *i2c) { @@ -403,7 +403,7 @@ STATIC void i2c_reset_after_error(I2C_HandleTypeDef *i2c) { } // bus was/is busy, need to reset the peripheral to get it to work again i2c_deinit(i2c); - i2c_init(i2c); + pyb_i2c_init(i2c); } void i2c_ev_irq_handler(mp_uint_t i2c_id) { @@ -563,7 +563,7 @@ STATIC void pyb_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki mp_printf(print, "I2C(%u)", i2c_num); } else { if (in_master_mode(self)) { - mp_printf(print, "I2C(%u, I2C.MASTER, baudrate=%u)", i2c_num, i2c_get_baudrate(self->i2c)); + mp_printf(print, "I2C(%u, I2C.MASTER, baudrate=%u)", i2c_num, pyb_i2c_get_baudrate(self->i2c)); } else { mp_printf(print, "I2C(%u, I2C.SLAVE, addr=0x%02x)", i2c_num, (self->i2c->Instance->OAR1 >> 1) & 0x7f); } @@ -612,7 +612,7 @@ STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, size_t n_args, co // init the I2C bus i2c_deinit(self->i2c); - i2c_init(self->i2c); + pyb_i2c_init(self->i2c); return mp_const_none; } @@ -680,10 +680,10 @@ STATIC mp_obj_t pyb_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_ return (mp_obj_t)i2c_obj; } -STATIC mp_obj_t pyb_i2c_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { +STATIC mp_obj_t pyb_i2c_init_(size_t 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_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_init_obj, 1, pyb_i2c_init_); /// \method deinit() /// Turn off the I2C bus. From 19778d0a3c8e819fd7e7408cf9081b25911f8a3c Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 24 Apr 2018 17:34:07 +1000 Subject: [PATCH 563/828] stm32/i2c: Add low-level I2C driver for F7 MCUs. --- ports/stm32/Makefile | 1 + ports/stm32/i2c.c | 234 +++++++++++++++++++++++++++++++++++++++++++ ports/stm32/i2c.h | 9 ++ 3 files changed, 244 insertions(+) create mode 100644 ports/stm32/i2c.c diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 4e185b7948..7daf4df4a9 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -216,6 +216,7 @@ SRC_C = \ pin_named_pins.c \ bufhelper.c \ dma.c \ + i2c.c \ pyb_i2c.c \ spi.c \ qspi.c \ diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c new file mode 100644 index 0000000000..7421ae1bd2 --- /dev/null +++ b/ports/stm32/i2c.c @@ -0,0 +1,234 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mperrno.h" +#include "py/mphal.h" +#include "i2c.h" + +#if MICROPY_HW_ENABLE_HW_I2C + +#if defined(STM32F7) + +#define I2C_POLL_TIMEOUT_MS (50) + +int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t freq) { + uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); + + // Init pins + if (!mp_hal_pin_config_alt(scl, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, AF_FN_I2C, i2c_id + 1)) { + return -MP_EPERM; + } + if (!mp_hal_pin_config_alt(sda, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, AF_FN_I2C, i2c_id + 1)) { + return -MP_EPERM; + } + + // Enable I2C peripheral clock + RCC->APB1ENR |= RCC_APB1ENR_I2C1EN << i2c_id; + volatile uint32_t tmp = RCC->APB1ENR; // delay after RCC clock enable + (void)tmp; + + // Initialise I2C peripheral + i2c->CR1 = 0; + i2c->CR2 = 0; + i2c->OAR1 = 0; + i2c->OAR2 = 0; + + // These timing values are for f_I2CCLK=54MHz and are only approximate + if (freq >= 1000000) { + i2c->TIMINGR = 0x50100103; + } else if (freq >= 400000) { + i2c->TIMINGR = 0x70330309; + } else if (freq >= 100000) { + i2c->TIMINGR = 0xb0420f13; + } else { + return -MP_EINVAL; + } + + i2c->TIMEOUTR = 0; + + return 0; +} + +STATIC int i2c_wait_cr2_clear(i2c_t *i2c, uint32_t mask) { + uint32_t t0 = HAL_GetTick(); + while (i2c->CR2 & mask) { + if (HAL_GetTick() - t0 >= I2C_POLL_TIMEOUT_MS) { + i2c->CR1 &= ~I2C_CR1_PE; + return -MP_ETIMEDOUT; + } + } + return 0; +} + +STATIC int i2c_wait_isr_set(i2c_t *i2c, uint32_t mask) { + uint32_t t0 = HAL_GetTick(); + while (!(i2c->ISR & mask)) { + if (HAL_GetTick() - t0 >= I2C_POLL_TIMEOUT_MS) { + i2c->CR1 &= ~I2C_CR1_PE; + return -MP_ETIMEDOUT; + } + } + return 0; +} + +// len = 0, 1 or N +int i2c_start_addr(i2c_t *i2c, int rd_wrn, uint16_t addr, size_t len, bool stop) { + // Enable the peripheral and send the START condition with slave address + i2c->CR1 |= I2C_CR1_PE; + i2c->CR2 = stop << I2C_CR2_AUTOEND_Pos + | (len > 1) << I2C_CR2_RELOAD_Pos + | (len > 0) << I2C_CR2_NBYTES_Pos + | rd_wrn << I2C_CR2_RD_WRN_Pos + | (addr & 0x7f) << 1; + i2c->CR2 |= I2C_CR2_START; + + // Wait for address to be sent + int ret; + if ((ret = i2c_wait_cr2_clear(i2c, I2C_CR2_START))) { + return ret; + } + + // Check if the slave responded or not + if (i2c->ISR & I2C_ISR_NACKF) { + // If we get a NACK then I2C periph releases the bus, so don't send STOP + i2c->CR1 &= ~I2C_CR1_PE; + return -MP_ENODEV; + } + + // Repurpose OAR1 to indicate that we loaded CR2 + i2c->OAR1 = 1; + + return 0; +} + +STATIC int i2c_check_stop(i2c_t *i2c) { + if (i2c->CR2 & I2C_CR2_AUTOEND) { + // Wait for the STOP condition and then disable the peripheral + int ret; + if ((ret = i2c_wait_isr_set(i2c, I2C_ISR_STOPF))) { + return ret; + } + i2c->CR1 &= ~I2C_CR1_PE; + } + + return 0; +} + +// next_len = 0 or N +int i2c_read(i2c_t *i2c, uint8_t *dest, size_t len, size_t next_len) { + if (i2c->OAR1) { + i2c->OAR1 = 0; + } else { + goto load_cr2; + } + + // Read in the data + while (len--) { + int ret; + if ((ret = i2c_wait_isr_set(i2c, I2C_ISR_RXNE))) { + return ret; + } + *dest++ = i2c->RXDR; + load_cr2: + if (len) { + i2c->CR2 = (i2c->CR2 & I2C_CR2_AUTOEND) + | (len + next_len > 1) << I2C_CR2_RELOAD_Pos + | 1 << I2C_CR2_NBYTES_Pos; + } + } + + if (!next_len) { + int ret; + if ((ret = i2c_check_stop(i2c))) { + return ret; + } + } + + return 0; +} + +// next_len = 0 or N +int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len) { + int num_acks = 0; + + if (i2c->OAR1) { + i2c->OAR1 = 0; + } else { + goto load_cr2; + } + + // Write out the data + while (len--) { + int ret; + if ((ret = i2c_wait_isr_set(i2c, I2C_ISR_TXE))) { + return ret; + } + i2c->TXDR = *src++; + if ((ret = i2c_wait_isr_set(i2c, I2C_ISR_TCR | I2C_ISR_TC | I2C_ISR_STOPF))) { + return ret; + } + if (i2c->ISR & I2C_ISR_NACKF) { + // Slave did not respond to byte so stop sending + break; + } + ++num_acks; + load_cr2: + if (len) { + i2c->CR2 = (i2c->CR2 & I2C_CR2_AUTOEND) + | (len + next_len > 1) << I2C_CR2_RELOAD_Pos + | 1 << I2C_CR2_NBYTES_Pos; + } + } + + if (!next_len) { + int ret; + if ((ret = i2c_check_stop(i2c))) { + return ret; + } + } + + return num_acks; +} + +int i2c_readfrom(i2c_t *i2c, uint16_t addr, uint8_t *dest, size_t len, bool stop) { + int ret; + if ((ret = i2c_start_addr(i2c, 1, addr, len, stop))) { + return ret; + } + return i2c_read(i2c, dest, len, 0); +} + +int i2c_writeto(i2c_t *i2c, uint16_t addr, const uint8_t *src, size_t len, bool stop) { + int ret; + if ((ret = i2c_start_addr(i2c, 0, addr, len, stop))) { + return ret; + } + return i2c_write(i2c, src, len, 0); +} + +#endif // defined(STM32F7) + +#endif // MICROPY_HW_ENABLE_HW_I2C diff --git a/ports/stm32/i2c.h b/ports/stm32/i2c.h index bf43f27281..5599f41235 100644 --- a/ports/stm32/i2c.h +++ b/ports/stm32/i2c.h @@ -53,4 +53,13 @@ uint32_t pyb_i2c_get_baudrate(I2C_HandleTypeDef *i2c); void i2c_ev_irq_handler(mp_uint_t i2c_id); void i2c_er_irq_handler(mp_uint_t i2c_id); +typedef I2C_TypeDef i2c_t; + +int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t freq); +int i2c_start_addr(i2c_t *i2c, int rd_wrn, uint16_t addr, size_t len, bool stop); +int i2c_read(i2c_t *i2c, uint8_t *dest, size_t len, size_t next_len); +int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len); +int i2c_readfrom(i2c_t *i2c, uint16_t addr, uint8_t *dest, size_t len, bool stop); +int i2c_writeto(i2c_t *i2c, uint16_t addr, const uint8_t *src, size_t len, bool stop); + #endif // MICROPY_INCLUDED_STM32_I2C_H From 9254f365d67ce58b4e90999fff314513a6c2413b Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 24 Apr 2018 17:34:42 +1000 Subject: [PATCH 564/828] stm32/machine_i2c: Provide hardware I2C for machine.I2C on F7 MCUs. --- ports/stm32/machine_i2c.c | 60 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c index 54e8425713..17d3f3ef47 100644 --- a/ports/stm32/machine_i2c.c +++ b/ports/stm32/machine_i2c.c @@ -416,6 +416,66 @@ timeout: return -MP_ETIMEDOUT; } +#elif defined(STM32F7) + +typedef struct _machine_hard_i2c_obj_t { + mp_obj_base_t base; + i2c_t *i2c; + mp_hal_pin_obj_t scl; + mp_hal_pin_obj_t sda; +} machine_hard_i2c_obj_t; + +STATIC const machine_hard_i2c_obj_t machine_hard_i2c_obj[] = { + #if defined(MICROPY_HW_I2C1_SCL) + {{&machine_hard_i2c_type}, I2C1, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA}, + #else + {{NULL}, NULL, NULL, NULL}, + #endif + #if defined(MICROPY_HW_I2C2_SCL) + {{&machine_hard_i2c_type}, I2C2, MICROPY_HW_I2C2_SCL, MICROPY_HW_I2C2_SDA}, + #else + {{NULL}, NULL, NULL, NULL}, + #endif + #if defined(MICROPY_HW_I2C3_SCL) + {{&machine_hard_i2c_type}, I2C3, MICROPY_HW_I2C3_SCL, MICROPY_HW_I2C3_SDA}, + #else + {{NULL}, NULL, NULL, NULL}, + #endif + #if defined(MICROPY_HW_I2C4_SCL) + {{&machine_hard_i2c_type}, I2C4, MICROPY_HW_I2C4_SCL, MICROPY_HW_I2C4_SDA}, + #else + {{NULL}, NULL, NULL, NULL}, + #endif +}; + +STATIC void machine_hard_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint32_t timingr = self->i2c->TIMINGR; + uint32_t presc = timingr >> 28; + uint32_t sclh = timingr >> 8 & 0xff; + uint32_t scll = timingr & 0xff; + uint32_t freq = HAL_RCC_GetPCLK1Freq() / (presc + 1) / (sclh + scll + 2); + mp_printf(print, "I2C(%u, scl=%q, sda=%q, freq=%u, timingr=0x%08x)", + self - &machine_hard_i2c_obj[0] + 1, + mp_hal_pin_name(self->scl), mp_hal_pin_name(self->sda), + freq, timingr); +} + +void machine_hard_i2c_init(machine_hard_i2c_obj_t *self, uint32_t freq, uint32_t timeout) { + (void)timeout; + i2c_init(self->i2c, self->scl, self->sda, freq); +} + +int machine_hard_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop) { + machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + return i2c_readfrom(self->i2c, addr, dest, len, stop); +} + +int machine_hard_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop) { + machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + return i2c_writeto(self->i2c, addr, src, len, stop); +} + #else // No hardware I2C driver for this MCU so use the software implementation From c7818032b160961bbd88a57926a78fcab297e4f2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 26 Apr 2018 17:14:51 +1000 Subject: [PATCH 565/828] docs/library: Add ussl module to library index for unix port. --- docs/library/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/library/index.rst b/docs/library/index.rst index af1a0ff697..d5678d37e3 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -87,6 +87,7 @@ it will fallback to loading the built-in ``ujson`` module. ure.rst uselect.rst usocket.rst + ussl.rst ustruct.rst utime.rst uzlib.rst From e1fe3abd0928c5e3545c546b02317aff72c72590 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 26 Apr 2018 20:19:31 +1000 Subject: [PATCH 566/828] esp32/mphalport: Use esp_timer_get_time instead of gettimeofday. It's more efficient and improves accuracy. --- ports/esp32/mphalport.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c index e588fc65a1..e299a196f8 100644 --- a/ports/esp32/mphalport.c +++ b/ports/esp32/mphalport.c @@ -27,7 +27,6 @@ */ #include -#include #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -86,35 +85,30 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) { } uint32_t mp_hal_ticks_ms(void) { - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000 + tv.tv_usec / 1000; + return esp_timer_get_time() / 1000; } uint32_t mp_hal_ticks_us(void) { - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000000 + tv.tv_usec; + return esp_timer_get_time(); } void mp_hal_delay_ms(uint32_t ms) { - struct timeval tv_start; - struct timeval tv_end; + uint64_t us = ms * 1000; uint64_t dt; - gettimeofday(&tv_start, NULL); + uint64_t t0 = esp_timer_get_time(); for (;;) { - gettimeofday(&tv_end, NULL); - dt = (tv_end.tv_sec - tv_start.tv_sec) * 1000 + (tv_end.tv_usec - tv_start.tv_usec) / 1000; - if (dt + portTICK_PERIOD_MS >= ms) { - // doing a vTaskDelay would take us beyound requested delay time + uint64_t t1 = esp_timer_get_time(); + dt = t1 - t0; + if (dt + portTICK_PERIOD_MS * 1000 >= us) { + // doing a vTaskDelay would take us beyond requested delay time break; } MICROPY_EVENT_POLL_HOOK vTaskDelay(1); } - if (dt < ms) { + if (dt < us) { // do the remaining delay accurately - ets_delay_us((ms - dt) * 1000); + mp_hal_delay_us(us - dt); } } From 4ed586528047d3eced28a9f4af11dbbe64fa99bb Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 26 Apr 2018 20:21:33 +1000 Subject: [PATCH 567/828] esp32/mphalport: Improve mp_hal_delay_us so it handles pending events. Thanks to @bboser for the initial idea and implementation. --- ports/esp32/mphalport.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c index e299a196f8..76f3e2413a 100644 --- a/ports/esp32/mphalport.c +++ b/ports/esp32/mphalport.c @@ -113,7 +113,28 @@ void mp_hal_delay_ms(uint32_t ms) { } void mp_hal_delay_us(uint32_t us) { - ets_delay_us(us); + // these constants are tested for a 240MHz clock + const uint32_t this_overhead = 5; + const uint32_t pend_overhead = 150; + + // return if requested delay is less than calling overhead + if (us < this_overhead) { + return; + } + us -= this_overhead; + + uint64_t t0 = esp_timer_get_time(); + for (;;) { + uint64_t dt = esp_timer_get_time() - t0; + if (dt >= us) { + return; + } + if (dt + pend_overhead < us) { + // we have enough time to service pending events + // (don't use MICROPY_EVENT_POLL_HOOK because it also yields) + mp_handle_pending(); + } + } } // this function could do with improvements (eg use ets_delay_us) From 527ba0426ce5e576f6cc4102fa547417743708a1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 Apr 2018 12:54:35 +1000 Subject: [PATCH 568/828] stm32/system_stm32: Reconfigure SysTick IRQ priority for L4 MCUs. After calling HAL_SYSTICK_Config the SysTick IRQ priority is set to 15, the lowest priority. This commit reconfigures the IRQ priority to the desired TICK_INT_PRIORITY value. --- ports/stm32/system_stm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c index 70bbb2a8bd..6bf9817ccb 100644 --- a/ports/stm32/system_stm32.c +++ b/ports/stm32/system_stm32.c @@ -598,8 +598,8 @@ void SystemClock_Config(void) HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1); HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); - HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); + HAL_NVIC_SetPriority(SysTick_IRQn, TICK_INT_PRIORITY, 0); #endif } From deaa46aa66230071d355c0ffd004ccf0cbefd8b9 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Tue, 24 Apr 2018 17:47:45 +0200 Subject: [PATCH 569/828] py/nlrthumb: Fix Clang support wrt use of "return 0". Clang defines __GNUC__ so we have to check for it specifically. --- py/nlrthumb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/py/nlrthumb.c b/py/nlrthumb.c index 7dbeac1b67..c283023551 100644 --- a/py/nlrthumb.c +++ b/py/nlrthumb.c @@ -76,8 +76,9 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { #endif ); - #if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)) + #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)) // Older versions of gcc give an error when naked functions don't return a value + // Additionally exclude Clang as it also defines __GNUC__ but doesn't need this statement return 0; #endif } From c0dd9be60635956114ab50aa0386235ca23f05fd Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 Apr 2018 15:16:45 +1000 Subject: [PATCH 570/828] stm32/boards/NUCLEO_H743ZI: Use priority 0 for SysTick IRQ. This follows how all other boards are configured. --- ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h index 19f9563ab0..97b141d49f 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h @@ -166,7 +166,7 @@ * @brief This is the HAL system configuration section */ #define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ -#define TICK_INT_PRIORITY ((uint32_t)0x0F) /*!< tick interrupt priority */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ #define USE_RTOS 0 #define USE_SD_TRANSCEIVER 0U /*!< use uSD Transceiver */ From 04dc4a5034bc9bbf8dbb21bd6767ea9d5053abcf Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 Apr 2018 23:49:21 +1000 Subject: [PATCH 571/828] esp32/mphalport: Improve mp_hal_stdout_tx_XXX functions. This makes way for enabling uos.dupterm(). --- ports/esp32/mphalport.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c index 76f3e2413a..6cc2621cac 100644 --- a/ports/esp32/mphalport.c +++ b/ports/esp32/mphalport.c @@ -27,6 +27,7 @@ */ #include +#include #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -52,36 +53,36 @@ int mp_hal_stdin_rx_chr(void) { } } -void mp_hal_stdout_tx_char(char c) { - uart_tx_one_char(c); - //mp_uos_dupterm_tx_strn(&c, 1); -} - void mp_hal_stdout_tx_str(const char *str) { - MP_THREAD_GIL_EXIT(); - while (*str) { - mp_hal_stdout_tx_char(*str++); - } - MP_THREAD_GIL_ENTER(); + mp_hal_stdout_tx_strn(str, strlen(str)); } void mp_hal_stdout_tx_strn(const char *str, uint32_t len) { MP_THREAD_GIL_EXIT(); - while (len--) { - mp_hal_stdout_tx_char(*str++); + for (uint32_t i = 0; i < len; ++i) { + uart_tx_one_char(str[i]); } MP_THREAD_GIL_ENTER(); } -void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) { - MP_THREAD_GIL_EXIT(); +// Efficiently convert "\n" to "\r\n" +void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { + const char *last = str; while (len--) { if (*str == '\n') { - mp_hal_stdout_tx_char('\r'); + if (str > last) { + mp_hal_stdout_tx_strn(last, str - last); + } + mp_hal_stdout_tx_strn("\r\n", 2); + ++str; + last = str; + } else { + ++str; } - mp_hal_stdout_tx_char(*str++); } - MP_THREAD_GIL_ENTER(); + if (str > last) { + mp_hal_stdout_tx_strn(last, str - last); + } } uint32_t mp_hal_ticks_ms(void) { From 98b05e36148655ac53383f4ccea37e15445a5c54 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 Apr 2018 23:51:00 +1000 Subject: [PATCH 572/828] esp32: Add support for and enable uos.dupterm(). --- ports/esp32/moduos.c | 12 +++++++++--- ports/esp32/mpconfigport.h | 1 + ports/esp32/mphalport.c | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/ports/esp32/moduos.c b/ports/esp32/moduos.c index 9f0e291a68..dc85136f3d 100644 --- a/ports/esp32/moduos.c +++ b/ports/esp32/moduos.c @@ -31,11 +31,11 @@ #include "esp_system.h" -#include "py/mpconfig.h" -#include "py/obj.h" #include "py/objstr.h" #include "py/runtime.h" #include "py/mperrno.h" +#include "py/mphal.h" +#include "extmod/misc.h" #include "extmod/vfs.h" #include "extmod/vfs_fat.h" #include "genhdr/mpversion.h" @@ -87,7 +87,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); #if MICROPY_PY_OS_DUPTERM STATIC mp_obj_t os_dupterm_notify(mp_obj_t obj_in) { (void)obj_in; - mp_hal_signal_dupterm_input(); + for (;;) { + int c = mp_uos_dupterm_rx_chr(); + if (c < 0) { + break; + } + ringbuf_put(&stdin_ringbuf, c); + } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_dupterm_notify_obj, os_dupterm_notify); diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 80594b1144..2f4acaf129 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -127,6 +127,7 @@ #define MICROPY_PY_UBINASCII_CRC32 (1) #define MICROPY_PY_URANDOM (1) #define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) +#define MICROPY_PY_OS_DUPTERM (1) #define MICROPY_PY_MACHINE (1) #define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new #define MICROPY_PY_MACHINE_PULSE (1) diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c index 6cc2621cac..353e1343b0 100644 --- a/ports/esp32/mphalport.c +++ b/ports/esp32/mphalport.c @@ -63,6 +63,7 @@ void mp_hal_stdout_tx_strn(const char *str, uint32_t len) { uart_tx_one_char(str[i]); } MP_THREAD_GIL_ENTER(); + mp_uos_dupterm_tx_strn(str, len); } // Efficiently convert "\n" to "\r\n" From 999c8b9711bf31ac375c09f35672e59b21d0aed4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 Apr 2018 23:53:45 +1000 Subject: [PATCH 573/828] esp32/modsocket: Add support for registering socket event callbacks. The esp8266 uses modlwip.c for its usocket implementation, which allows to easily support callbacks on socket events (like when a socket becomes ready for reading). This is not as easy to do for the esp32 which uses the ESP-IDF-provided lwIP POSIX socket API. Socket events are needed to get WebREPL working, and this patch provides a way for such events to work by explicitly polling registered sockets for readability, and then calling the associated callback if the socket is readable. --- ports/esp32/main.c | 2 + ports/esp32/modnetwork.h | 2 + ports/esp32/modsocket.c | 95 ++++++++++++++++++++++++++++++++++++++ ports/esp32/mpconfigport.h | 8 ++++ 4 files changed, 107 insertions(+) diff --git a/ports/esp32/main.c b/ports/esp32/main.c index eebf183cd6..2fa86fd3c9 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -47,6 +47,7 @@ #include "lib/utils/pyexec.h" #include "uart.h" #include "modmachine.h" +#include "modnetwork.h" #include "mpthreadport.h" // MicroPython runs as a task under FreeRTOS @@ -110,6 +111,7 @@ soft_reset: // deinitialise peripherals machine_pins_deinit(); + usocket_events_deinit(); mp_deinit(); fflush(stdout); diff --git a/ports/esp32/modnetwork.h b/ports/esp32/modnetwork.h index d9f56591e2..b8dc1b8528 100644 --- a/ports/esp32/modnetwork.h +++ b/ports/esp32/modnetwork.h @@ -31,4 +31,6 @@ enum { PHY_LAN8720, PHY_TLK110 }; MP_DECLARE_CONST_FUN_OBJ_KW(get_lan_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj); +void usocket_events_deinit(void); + #endif diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 8b3c280635..94cf3cc57c 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -47,6 +47,7 @@ #include "py/mperrno.h" #include "lib/netutils/netutils.h" #include "tcpip_adapter.h" +#include "modnetwork.h" #include "lwip/sockets.h" #include "lwip/netdb.h" @@ -63,10 +64,79 @@ typedef struct _socket_obj_t { uint8_t type; uint8_t proto; unsigned int retries; + #if MICROPY_PY_USOCKET_EVENTS + mp_obj_t events_callback; + struct _socket_obj_t *events_next; + #endif } socket_obj_t; void _socket_settimeout(socket_obj_t *sock, uint64_t timeout_ms); +#if MICROPY_PY_USOCKET_EVENTS +// Support for callbacks on asynchronous socket events (when socket becomes readable) + +// This divisor is used to reduce the load on the system, so it doesn't poll sockets too often +#define USOCKET_EVENTS_DIVISOR (8) + +STATIC uint8_t usocket_events_divisor; +STATIC socket_obj_t *usocket_events_head; + +void usocket_events_deinit(void) { + usocket_events_head = NULL; +} + +// Assumes the socket is not already in the linked list, and adds it +STATIC void usocket_events_add(socket_obj_t *sock) { + sock->events_next = usocket_events_head; + usocket_events_head = sock; +} + +// Assumes the socket is already in the linked list, and removes it +STATIC void usocket_events_remove(socket_obj_t *sock) { + for (socket_obj_t **s = &usocket_events_head;; s = &(*s)->events_next) { + if (*s == sock) { + *s = (*s)->events_next; + return; + } + } +} + +// Polls all registered sockets for readability and calls their callback if they are readable +void usocket_events_handler(void) { + if (usocket_events_head == NULL) { + return; + } + if (--usocket_events_divisor) { + return; + } + usocket_events_divisor = USOCKET_EVENTS_DIVISOR; + + fd_set rfds; + FD_ZERO(&rfds); + int max_fd = 0; + + for (socket_obj_t *s = usocket_events_head; s != NULL; s = s->events_next) { + FD_SET(s->fd, &rfds); + max_fd = MAX(max_fd, s->fd); + } + + // Poll the sockets + struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 }; + int r = select(max_fd + 1, &rfds, NULL, NULL, &timeout); + if (r <= 0) { + return; + } + + // Call the callbacks + for (socket_obj_t *s = usocket_events_head; s != NULL; s = s->events_next) { + if (FD_ISSET(s->fd, &rfds)) { + mp_call_function_1_protected(s->events_callback, s); + } + } +} + +#endif // MICROPY_PY_USOCKET_EVENTS + NORETURN static void exception_from_errno(int _errno) { // Here we need to convert from lwip errno values to MicroPython's standard ones if (_errno == EINPROGRESS) { @@ -209,6 +279,25 @@ STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { break; } + #if MICROPY_PY_USOCKET_EVENTS + // level: SOL_SOCKET + // special "register callback" option + case 20: { + if (args[3] == mp_const_none) { + if (self->events_callback != MP_OBJ_NULL) { + usocket_events_remove(self); + self->events_callback = MP_OBJ_NULL; + } + } else { + if (self->events_callback == MP_OBJ_NULL) { + usocket_events_add(self); + } + self->events_callback = args[3]; + } + break; + } + #endif + // level: IPPROTO_IP case IP_ADD_MEMBERSHIP: { mp_buffer_info_t bufinfo; @@ -439,6 +528,12 @@ STATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintpt return ret; } else if (request == MP_STREAM_CLOSE) { if (socket->fd >= 0) { + #if MICROPY_PY_USOCKET_EVENTS + if (socket->events_callback != MP_OBJ_NULL) { + usocket_events_remove(socket); + socket->events_callback = MP_OBJ_NULL; + } + #endif int ret = lwip_close_r(socket->fd); if (ret != 0) { *errcode = errno; diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 2f4acaf129..0239de4080 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -221,11 +221,18 @@ extern const struct _mp_obj_module_t mp_module_onewire; #define MICROPY_BEGIN_ATOMIC_SECTION() portENTER_CRITICAL_NESTED() #define MICROPY_END_ATOMIC_SECTION(state) portEXIT_CRITICAL_NESTED(state) +#if MICROPY_PY_USOCKET_EVENTS +#define MICROPY_PY_USOCKET_EVENTS_HANDLER extern void usocket_events_handler(void); usocket_events_handler(); +#else +#define MICROPY_PY_USOCKET_EVENTS_HANDLER +#endif + #if MICROPY_PY_THREAD #define MICROPY_EVENT_POLL_HOOK \ do { \ extern void mp_handle_pending(void); \ mp_handle_pending(); \ + MICROPY_PY_USOCKET_EVENTS_HANDLER \ MP_THREAD_GIL_EXIT(); \ MP_THREAD_GIL_ENTER(); \ } while (0); @@ -234,6 +241,7 @@ extern const struct _mp_obj_module_t mp_module_onewire; do { \ extern void mp_handle_pending(void); \ mp_handle_pending(); \ + MICROPY_PY_USOCKET_EVENTS_HANDLER \ asm("waiti 0"); \ } while (0); #endif From c1d4352e6539fc042480017b63592c2622e955e7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 Apr 2018 23:57:57 +1000 Subject: [PATCH 574/828] esp32/mpconfigport: Enable webrepl module and socket events. --- ports/esp32/mpconfigport.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 0239de4080..b36bd2ebc9 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -142,7 +142,9 @@ #define MICROPY_SSL_MBEDTLS (1) #define MICROPY_PY_USSL_FINALISER (1) #define MICROPY_PY_WEBSOCKET (1) +#define MICROPY_PY_WEBREPL (1) #define MICROPY_PY_FRAMEBUF (1) +#define MICROPY_PY_USOCKET_EVENTS (MICROPY_PY_WEBREPL) // fatfs configuration #define MICROPY_FATFS_ENABLE_LFN (1) From 23e9c3bca7eb40566ffd4b6cd57b9b4e1f19ad30 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 Apr 2018 23:58:51 +1000 Subject: [PATCH 575/828] esp32/modules: Add support scripts for WebREPL. WebREPL now works on the esp32 in the same way it does on esp8266. --- ports/esp32/modules/inisetup.py | 4 ++++ ports/esp32/modules/webrepl.py | 1 + ports/esp32/modules/webrepl_setup.py | 1 + ports/esp32/modules/websocket_helper.py | 1 + 4 files changed, 7 insertions(+) create mode 120000 ports/esp32/modules/webrepl.py create mode 120000 ports/esp32/modules/webrepl_setup.py create mode 120000 ports/esp32/modules/websocket_helper.py diff --git a/ports/esp32/modules/inisetup.py b/ports/esp32/modules/inisetup.py index 45bce82cc2..0e9c72fe86 100644 --- a/ports/esp32/modules/inisetup.py +++ b/ports/esp32/modules/inisetup.py @@ -34,5 +34,9 @@ def setup(): with open("boot.py", "w") as f: f.write("""\ # This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() """) return vfs diff --git a/ports/esp32/modules/webrepl.py b/ports/esp32/modules/webrepl.py new file mode 120000 index 0000000000..2a3987a729 --- /dev/null +++ b/ports/esp32/modules/webrepl.py @@ -0,0 +1 @@ +../../esp8266/modules/webrepl.py \ No newline at end of file diff --git a/ports/esp32/modules/webrepl_setup.py b/ports/esp32/modules/webrepl_setup.py new file mode 120000 index 0000000000..999888bf13 --- /dev/null +++ b/ports/esp32/modules/webrepl_setup.py @@ -0,0 +1 @@ +../../esp8266/modules/webrepl_setup.py \ No newline at end of file diff --git a/ports/esp32/modules/websocket_helper.py b/ports/esp32/modules/websocket_helper.py new file mode 120000 index 0000000000..4bcf3bcb6a --- /dev/null +++ b/ports/esp32/modules/websocket_helper.py @@ -0,0 +1 @@ +../../esp8266/modules/websocket_helper.py \ No newline at end of file From 8c12f1d916b119596c115ed7ce73eaf3f3a9cd7a Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Sun, 1 Apr 2018 03:20:21 +0200 Subject: [PATCH 576/828] stm32/adc: Add support for H7 MCU series. ADC3 is used because the H7's internal ADC channels are connected to ADC3 and the uPy driver doesn't support more than one ADC. Only 12-bit resolution is supported because 12 is hard-coded and 14/16 bits are not recommended on some ADC3 pins (see errata). Values from internal ADC channels are known to give wrong values at present. --- ports/stm32/adc.c | 57 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 9f126650b9..fdb31ba9c1 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -51,7 +51,11 @@ /// val = adc.read_core_vref() # read MCU VREF /* ADC defintions */ +#if defined(STM32H7) +#define ADCx (ADC3) +#else #define ADCx (ADC1) +#endif #define ADCx_CLK_ENABLE __HAL_RCC_ADC1_CLK_ENABLE #define ADC_NUM_CHANNELS (19) @@ -77,6 +81,15 @@ #define ADC_CAL1 ((uint16_t*)(ADC_CAL_ADDRESS + 2)) #define ADC_CAL2 ((uint16_t*)(ADC_CAL_ADDRESS + 4)) +#elif defined(STM32H7) + +#define ADC_FIRST_GPIO_CHANNEL (0) +#define ADC_LAST_GPIO_CHANNEL (16) +#define ADC_CAL_ADDRESS (0x1FF1E860) +#define ADC_CAL1 ((uint16_t*)(0x1FF1E820)) +#define ADC_CAL2 ((uint16_t*)(0x1FF1E840)) +#define ADC_CHANNEL_VBAT ADC_CHANNEL_VBAT_DIV4 + #elif defined(STM32L4) #define ADC_FIRST_GPIO_CHANNEL (1) @@ -103,6 +116,8 @@ defined(STM32F746xx) || defined(STM32F767xx) || \ defined(STM32F769xx) || defined(STM32F446xx) #define VBAT_DIV (4) +#elif defined(STM32H743xx) +#define VBAT_DIV (4) #elif defined(STM32L475xx) || defined(STM32L476xx) #define VBAT_DIV (3) #else @@ -143,7 +158,7 @@ STATIC bool is_adcx_channel(int channel) { #if defined(STM32F411xE) // The HAL has an incorrect IS_ADC_CHANNEL macro for the F411 so we check for temp return IS_ADC_CHANNEL(channel) || channel == ADC_CHANNEL_TEMPSENSOR; -#elif defined(STM32F4) || defined(STM32F7) +#elif defined(STM32F4) || defined(STM32F7) || defined(STM32H7) return IS_ADC_CHANNEL(channel); #elif defined(STM32L4) ADC_HandleTypeDef handle; @@ -158,7 +173,7 @@ STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) { uint32_t tickstart = HAL_GetTick(); #if defined(STM32F4) || defined(STM32F7) while ((ADCx->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC) { -#elif defined(STM32L4) +#elif defined(STM32H7) || defined(STM32L4) while (READ_BIT(ADCx->ISR, ADC_FLAG_EOC) != ADC_FLAG_EOC) { #else #error Unsupported processor @@ -172,6 +187,9 @@ STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) { STATIC void adcx_clock_enable(void) { #if defined(STM32F4) || defined(STM32F7) ADCx_CLK_ENABLE(); +#elif defined(STM32H7) + __HAL_RCC_ADC3_CLK_ENABLE(); + __HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP); #elif defined(STM32L4) __HAL_RCC_ADC_CLK_ENABLE(); #else @@ -187,26 +205,41 @@ STATIC void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) { adch->Init.ContinuousConvMode = DISABLE; adch->Init.DiscontinuousConvMode = DISABLE; adch->Init.NbrOfDiscConversion = 0; - adch->Init.DataAlign = ADC_DATAALIGN_RIGHT; adch->Init.NbrOfConversion = 1; - adch->Init.DMAContinuousRequests = DISABLE; adch->Init.EOCSelection = ADC_EOC_SINGLE_CONV; adch->Init.ExternalTrigConv = ADC_SOFTWARE_START; adch->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; #if defined(STM32F4) || defined(STM32F7) adch->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; adch->Init.ScanConvMode = DISABLE; + adch->Init.DataAlign = ADC_DATAALIGN_RIGHT; + adch->Init.DMAContinuousRequests = DISABLE; + #elif defined(STM32H7) + adch->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; + adch->Init.BoostMode = ENABLE; + adch->Init.ScanConvMode = DISABLE; + adch->Init.LowPowerAutoWait = DISABLE; + adch->Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; + adch->Init.OversamplingMode = DISABLE; + adch->Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE; + adch->Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR; #elif defined(STM32L4) adch->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; adch->Init.ScanConvMode = ADC_SCAN_DISABLE; adch->Init.LowPowerAutoWait = DISABLE; adch->Init.Overrun = ADC_OVR_DATA_PRESERVED; adch->Init.OversamplingMode = DISABLE; + adch->Init.DataAlign = ADC_DATAALIGN_RIGHT; + adch->Init.DMAContinuousRequests = DISABLE; #else #error Unsupported processor #endif HAL_ADC_Init(adch); + + #if defined(STM32H7) + HAL_ADCEx_Calibration_Start(adch, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED); + #endif } STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { @@ -221,7 +254,7 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { mp_hal_gpio_clock_enable(pin->gpio); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Pin = pin->pin_mask; -#if defined(STM32F4) || defined(STM32F7) +#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) GPIO_InitStructure.Mode = GPIO_MODE_ANALOG; #elif defined(STM32L4) GPIO_InitStructure.Mode = GPIO_MODE_ANALOG_ADC_CONTROL; @@ -251,6 +284,12 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) sConfig.Rank = 1; #if defined(STM32F4) || defined(STM32F7) sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES; +#elif defined(STM32H7) + sConfig.SamplingTime = ADC_SAMPLETIME_8CYCLES_5; + sConfig.SingleDiff = ADC_SINGLE_ENDED; + sConfig.OffsetNumber = ADC_OFFSET_NONE; + sConfig.OffsetRightShift = DISABLE; + sConfig.OffsetSignedSaturation = DISABLE; #elif defined(STM32L4) sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5; sConfig.SingleDiff = ADC_SINGLE_ENDED; @@ -415,7 +454,7 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_ // for subsequent samples we can just set the "start sample" bit #if defined(STM32F4) || defined(STM32F7) ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART; -#elif defined(STM32L4) +#elif defined(STM32H7) || defined(STM32L4) SET_BIT(ADCx->CR, ADC_CR_ADSTART); #else #error Unsupported processor @@ -525,7 +564,7 @@ STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_i // ADC is started: set the "start sample" bit #if defined(STM32F4) || defined(STM32F7) ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART; - #elif defined(STM32L4) + #elif defined(STM32H7) || defined(STM32L4) SET_BIT(ADCx->CR, ADC_CR_ADSTART); #else #error Unsupported processor @@ -580,7 +619,9 @@ typedef struct _pyb_adc_all_obj_t { void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_mask) { switch (resolution) { + #if !defined(STM32H7) case 6: resolution = ADC_RESOLUTION_6B; break; + #endif case 8: resolution = ADC_RESOLUTION_8B; break; case 10: resolution = ADC_RESOLUTION_10B; break; case 12: resolution = ADC_RESOLUTION_12B; break; @@ -613,7 +654,9 @@ int adc_get_resolution(ADC_HandleTypeDef *adcHandle) { uint32_t res_reg = ADC_GET_RESOLUTION(adcHandle); switch (res_reg) { + #if !defined(STM32H7) case ADC_RESOLUTION_6B: return 6; + #endif case ADC_RESOLUTION_8B: return 8; case ADC_RESOLUTION_10B: return 10; } From 28c9824c51a877deea97f87e0ce01561d0d93595 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Wed, 11 Apr 2018 14:19:40 +0200 Subject: [PATCH 577/828] stm32/boards/NUCLEO_H743ZI: Enable ADC peripheral. --- ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h index d23c5bab04..117e7f3f60 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h @@ -3,7 +3,7 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_RNG (1) -#define MICROPY_HW_ENABLE_ADC (0) +#define MICROPY_HW_ENABLE_ADC (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_USB (1) #define MICROPY_HW_HAS_SWITCH (1) From 9f1eafc38092213bf59cd5dfdd803249077729c3 Mon Sep 17 00:00:00 2001 From: Mike Wadsten Date: Mon, 30 Apr 2018 20:59:23 -0500 Subject: [PATCH 578/828] tests/io/bytesio_ext2: Remove dependency on specific EINVAL value If MICROPY_USE_INTERNAL_ERRNO is disabled, MP_EINVAL is not guaranteed to have the value 22, so we cannot depend on OSError(22,). Instead, to support any given port's errno values, without relying on uerrno, we just check that the args[0] is positive. --- tests/io/bytesio_ext2.py | 2 +- tests/io/bytesio_ext2.py.exp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/io/bytesio_ext2.py b/tests/io/bytesio_ext2.py index c07ad900c9..8f624fd58c 100644 --- a/tests/io/bytesio_ext2.py +++ b/tests/io/bytesio_ext2.py @@ -10,4 +10,4 @@ except Exception as e: # CPython throws ValueError, but MicroPython has consistent stream # interface, so BytesIO raises the same error as a real file, which # is OSError(EINVAL). - print(repr(e)) + print(type(e), e.args[0] > 0) diff --git a/tests/io/bytesio_ext2.py.exp b/tests/io/bytesio_ext2.py.exp index b52e4978aa..724aaf63a2 100644 --- a/tests/io/bytesio_ext2.py.exp +++ b/tests/io/bytesio_ext2.py.exp @@ -1 +1 @@ -OSError(22,) + True From 96740be3574d91279ca883adbb19b976413ef52b Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 26 Apr 2018 15:02:59 +1000 Subject: [PATCH 579/828] py/mperrno: Define MP_EWOULDBLOCK as EWOULDBLOCK, not EAGAIN. Most modern systems have EWOULDBLOCK aliased to EAGAIN, ie they have the same value. But some systems use different values for these errnos and if a uPy port is using the system errno values (ie not the internal uPy values) then it's important to be able to distinguish EWOULDBLOCK from EAGAIN. Eg if a system call returned EWOULDBLOCK it must be possible to check for this return value, and this patch makes this now possible. --- py/mperrno.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/mperrno.h b/py/mperrno.h index f439f65554..0cad75a17c 100644 --- a/py/mperrno.h +++ b/py/mperrno.h @@ -122,7 +122,7 @@ #define MP_EPIPE EPIPE #define MP_EDOM EDOM #define MP_ERANGE ERANGE -#define MP_EWOULDBLOCK EAGAIN +#define MP_EWOULDBLOCK EWOULDBLOCK #define MP_EOPNOTSUPP EOPNOTSUPP #define MP_EAFNOSUPPORT EAFNOSUPPORT #define MP_EADDRINUSE EADDRINUSE From d43c7377564b3e1be36f627a465df2c5779a1ae8 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Tue, 24 Apr 2018 17:43:14 +0200 Subject: [PATCH 580/828] py/stream: Use uPy errno instead of system's for non-blocking check. This is a more consistent use of errno codes. For example, it may be that a stream returns MP_EAGAIN but the mp_is_nonblocking_error() macro doesn't catch this value because it checks for EAGAIN instead (which may have a different value than MP_EAGAIN when MICROPY_USE_INTERNAL_ERRNO is enabled). --- py/stream.c | 7 ------- py/stream.h | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/py/stream.c b/py/stream.c index f51f634b6f..393988d2c1 100644 --- a/py/stream.c +++ b/py/stream.c @@ -32,13 +32,6 @@ #include "py/stream.h" #include "py/runtime.h" -#if MICROPY_STREAMS_NON_BLOCK -#include -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) -#define EWOULDBLOCK 140 -#endif -#endif - // This file defines generic Python stream read/write methods which // dispatch to the underlying stream interface of an object. diff --git a/py/stream.h b/py/stream.h index a7d8d08f14..a1d1c4f8af 100644 --- a/py/stream.h +++ b/py/stream.h @@ -107,7 +107,7 @@ int mp_stream_posix_fsync(mp_obj_t stream); #endif #if MICROPY_STREAMS_NON_BLOCK -#define mp_is_nonblocking_error(errno) ((errno) == EAGAIN || (errno) == EWOULDBLOCK) +#define mp_is_nonblocking_error(errno) ((errno) == MP_EAGAIN || (errno) == MP_EWOULDBLOCK) #else #define mp_is_nonblocking_error(errno) (0) #endif From 298c072433f41f5b2a2813df423ddc3212e96792 Mon Sep 17 00:00:00 2001 From: Andreas Valder Date: Mon, 20 Nov 2017 17:03:38 +0100 Subject: [PATCH 581/828] esp32: Add support for the esp32's ULP. The ULP is available as esp32.ULP(). See README.ulp.md for basic usage. --- ports/esp32/Makefile | 7 +++ ports/esp32/README.ulp.md | 126 ++++++++++++++++++++++++++++++++++++++ ports/esp32/esp32_ulp.c | 97 +++++++++++++++++++++++++++++ ports/esp32/modesp32.c | 3 + ports/esp32/modesp32.h | 2 + ports/esp32/sdkconfig.h | 2 +- 6 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 ports/esp32/README.ulp.md create mode 100644 ports/esp32/esp32_ulp.c diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index d2d6192b5f..0d9e074286 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -83,6 +83,7 @@ INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip/posix INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/include INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/port/include INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/include +INC_ESPCOMP += -I$(ESPCOMP)/ulp/include INC_ESPCOMP += -I$(ESPCOMP)/vfs/include INC_ESPCOMP += -I$(ESPCOMP)/newlib/platform_include INC_ESPCOMP += -I$(ESPCOMP)/xtensa-debug-module/include @@ -148,6 +149,7 @@ SRC_C = \ network_lan.c \ modsocket.c \ modesp.c \ + esp32_ulp.c \ modesp32.c \ moduhashlib.c \ espneopixel.c \ @@ -417,6 +419,10 @@ ESPIDF_SPI_FLASH_O = $(addprefix $(ESPCOMP)/spi_flash/,\ flash_ops.o \ ) +ESPIDF_ULP_O = $(addprefix $(ESPCOMP)/ulp/,\ + ulp.o \ + ) + $(BUILD)/$(ESPCOMP)/lwip/%.o: CFLAGS += -Wno-address -Wno-unused-variable -Wno-unused-but-set-variable ESPIDF_LWIP_O = $(addprefix $(ESPCOMP)/lwip/,\ api/pppapi.o \ @@ -605,6 +611,7 @@ OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NGHTTP_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NVS_FLASH_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_OPENSSL_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SPI_FLASH_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ULP_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_WPA_SUPPLICANT_O)) ################################################################################ # Main targets diff --git a/ports/esp32/README.ulp.md b/ports/esp32/README.ulp.md new file mode 100644 index 0000000000..cbc5771a90 --- /dev/null +++ b/ports/esp32/README.ulp.md @@ -0,0 +1,126 @@ +# ULP + +To compile binarys for the ulp you need the ulp toolkit. Download it from https://github.com/espressif/binutils-esp32ulp/wiki#downloads +Then extract it, then add ```esp32ulp-elf-binutils/bin``` to your PATH + +## Example Makefile + +```make +ULP_S_SOURCES := main.S +ULP_APP_NAME := test +ULP_LD_SCRIPT := esp32.ulp.ld + +SRC_PATH := src +BUILD_PATH := build + +include $(ESPIDF)/components/ulp/Makefile.projbuild + +ULP_ELF := $(ULP_APP_NAME).elf +ULP_MAP := $(ULP_ELF:.elf=.map) +ULP_SYM := $(ULP_ELF:.elf=.sym) +ULP_BIN := $(ULP_ELF:.elf=.bin) +ULP_EXPORTS_LD := $(ULP_ELF:.elf=.ld) +ULP_EXPORTS_HEADER := $(ULP_ELF:.elf=.h) + +ULP_OBJECTS := $(notdir $(ULP_S_SOURCES:.S=.ulp.o)) +ULP_DEP := $(notdir $(ULP_S_SOURCES:.S=.ulp.d)) $(ULP_LD_SCRIPT:.ld=.d) +ULP_PREPROCESSED := $(notdir $(ULP_S_SOURCES:.S=.ulp.pS)) +ULP_LISTINGS := $(notdir $(ULP_S_SOURCES:.S=.ulp.lst)) + +.PHONY: all clean + +all: $(BUILD_PATH) $(BUILD_PATH)/$(ULP_BIN) + +clean: + rm -rf $(BUILD_PATH) + +$(BUILD_PATH): + mkdir $@ + +# Generate preprocessed linker file. +$(BUILD_PATH)/$(ULP_APP_NAME).ld: $(SRC_PATH)/$(ULP_LD_SCRIPT) + cpp -P $< -o $@ + +# Generate preprocessed assembly files. +# To inspect these preprocessed files, add a ".PRECIOUS: %.ulp.pS" rule. +$(BUILD_PATH)/%.ulp.pS: $(SRC_PATH)/%.S + cpp $< -o $@ + +# Compiled preprocessed files into object files. +$(BUILD_PATH)/%.ulp.o: $(BUILD_PATH)/%.ulp.pS + $(ULP_AS) -al=$(patsubst %.ulp.o,%.ulp.lst,$@) -o $@ $< + +# Link object files and generate map file +$(BUILD_PATH)/$(ULP_ELF): $(BUILD_PATH)/$(ULP_OBJECTS) $(BUILD_PATH)/$(ULP_APP_NAME).ld + $(ULP_LD) -o $@ -A elf32-esp32ulp -Map=$(BUILD_PATH)/$(ULP_MAP) -T $(BUILD_PATH)/$(ULP_APP_NAME).ld $< + +# Dump the list of global symbols in a convenient format. +$(ULP_SYM): $(ULP_ELF) + $(ULP_NM) -g -f posix $< > $@ + +# Dump the binary for inclusion into the project +$(BUILD_PATH)/$(ULP_BIN): $(BUILD_PATH)/$(ULP_ELF) + $(ULP_OBJCOPY) -O binary $< $@ +``` + +## Example linker script for the ulp +``` +#define ULP_BIN_MAGIC 0x00706c75 +#define HEADER_SIZE 12 +#define CONFIG_ULP_COPROC_RESERVE_MEM 4096 + +MEMORY +{ + ram(RW) : ORIGIN = 0, LENGTH = CONFIG_ULP_COPROC_RESERVE_MEM +} + +SECTIONS +{ + .text : AT(HEADER_SIZE) + { + *(.text) + } >ram + .data : + { + . = ALIGN(4); + *(.data) + } >ram + .bss : + { + . = ALIGN(4); + *(.bss) + } >ram + + .header : AT(0) + { + LONG(ULP_BIN_MAGIC) + SHORT(LOADADDR(.text)) + SHORT(SIZEOF(.text)) + SHORT(SIZEOF(.data)) + SHORT(SIZEOF(.bss)) + } +} +``` + +## Example ulp code +```asm +move R3, 99 +move R0, 10 + +# mem[R0+0] = R3 +st R3, R0, 0 + +HALT +``` + +## Example python code using the ulp +```python +import esp32 +import time + +u = esp32.ULP() +with open('test.bin', 'rb') as f: + b = f.read() +u.load_binary(0,b) +u.run(0) +``` diff --git a/ports/esp32/esp32_ulp.c b/ports/esp32/esp32_ulp.c new file mode 100644 index 0000000000..3772639f44 --- /dev/null +++ b/ports/esp32/esp32_ulp.c @@ -0,0 +1,97 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 "Andreas Valder" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" + +#include "esp32/ulp.h" +#include "esp_err.h" + +typedef struct _esp32_ulp_obj_t { + mp_obj_base_t base; +} esp32_ulp_obj_t; + +const mp_obj_type_t esp32_ulp_type; + +// singleton ULP object +STATIC const esp32_ulp_obj_t esp32_ulp_obj = {{&esp32_ulp_type}}; + +STATIC mp_obj_t esp32_ulp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // return constant object + return (mp_obj_t)&esp32_ulp_obj; +} + +STATIC mp_obj_t esp32_ulp_set_wakeup_period(mp_obj_t self_in, mp_obj_t period_index_in, mp_obj_t period_us_in) { + mp_uint_t period_index = mp_obj_get_int(period_index_in); + mp_uint_t period_us = mp_obj_get_int(period_us_in); + int _errno = ulp_set_wakeup_period(period_index, period_us); + if (_errno != ESP_OK) { + mp_raise_OSError(_errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_ulp_set_wakeup_period_obj, esp32_ulp_set_wakeup_period); + +STATIC mp_obj_t esp32_ulp_load_binary(mp_obj_t self_in, mp_obj_t load_addr_in, mp_obj_t program_binary_in) { + mp_uint_t load_addr = mp_obj_get_int(load_addr_in); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(program_binary_in, &bufinfo, MP_BUFFER_READ); + + int _errno = ulp_load_binary(load_addr, bufinfo.buf, bufinfo.len/sizeof(uint32_t)); + if (_errno != ESP_OK) { + mp_raise_OSError(_errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_ulp_load_binary_obj, esp32_ulp_load_binary); + +STATIC mp_obj_t esp32_ulp_run(mp_obj_t self_in, mp_obj_t entry_point_in) { + mp_uint_t entry_point = mp_obj_get_int(entry_point_in); + int _errno = ulp_run(entry_point/sizeof(uint32_t)); + if (_errno != ESP_OK) { + mp_raise_OSError(_errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp32_ulp_run_obj, esp32_ulp_run); + +STATIC const mp_rom_map_elem_t esp32_ulp_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_set_wakeup_period), MP_ROM_PTR(&esp32_ulp_set_wakeup_period_obj) }, + { MP_ROM_QSTR(MP_QSTR_load_binary), MP_ROM_PTR(&esp32_ulp_load_binary_obj) }, + { MP_ROM_QSTR(MP_QSTR_run), MP_ROM_PTR(&esp32_ulp_run_obj) }, + { MP_ROM_QSTR(MP_QSTR_RESERVE_MEM), MP_ROM_INT(CONFIG_ULP_COPROC_RESERVE_MEM) }, +}; +STATIC MP_DEFINE_CONST_DICT(esp32_ulp_locals_dict, esp32_ulp_locals_dict_table); + +const mp_obj_type_t esp32_ulp_type = { + { &mp_type_type }, + .name = MP_QSTR_ULP, + .make_new = esp32_ulp_make_new, + .locals_dict = (mp_obj_t)&esp32_ulp_locals_dict, +}; diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c index 6d18e0add1..bab78e9543 100644 --- a/ports/esp32/modesp32.c +++ b/ports/esp32/modesp32.c @@ -126,6 +126,9 @@ STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_wake_on_touch), (mp_obj_t)&esp32_wake_on_touch_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_wake_on_ext0), (mp_obj_t)&esp32_wake_on_ext0_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_wake_on_ext1), (mp_obj_t)&esp32_wake_on_ext1_obj }, + + { MP_ROM_QSTR(MP_QSTR_ULP), MP_ROM_PTR(&esp32_ulp_type) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_WAKEUP_ALL_LOW), mp_const_false }, { MP_OBJ_NEW_QSTR(MP_QSTR_WAKEUP_ANY_HIGH), mp_const_true }, }; diff --git a/ports/esp32/modesp32.h b/ports/esp32/modesp32.h index 83532e052f..1d18cb41fb 100644 --- a/ports/esp32/modesp32.h +++ b/ports/esp32/modesp32.h @@ -26,4 +26,6 @@ #define RTC_LAST_EXT_PIN 39 #define RTC_IS_VALID_EXT_PIN(pin_id) ((1ll << (pin_id)) & RTC_VALID_EXT_PINS) +extern const mp_obj_type_t esp32_ulp_type; + #endif // MICROPY_INCLUDED_ESP32_MODESP32_H diff --git a/ports/esp32/sdkconfig.h b/ports/esp32/sdkconfig.h index 113c0395fa..ff25afaf2d 100644 --- a/ports/esp32/sdkconfig.h +++ b/ports/esp32/sdkconfig.h @@ -5,7 +5,7 @@ #define CONFIG_TRACEMEM_RESERVE_DRAM 0x0 #define CONFIG_BT_RESERVE_DRAM 0x0 -#define CONFIG_ULP_COPROC_RESERVE_MEM 0 +#define CONFIG_ULP_COPROC_RESERVE_MEM 2040 #define CONFIG_PHY_DATA_OFFSET 0xf000 #define CONFIG_APP_OFFSET 0x10000 From d8fdb77ac91b578d851b873a004b530b42313cf1 Mon Sep 17 00:00:00 2001 From: Lars Kellogg-Stedman Date: Mon, 9 Apr 2018 15:34:18 -0400 Subject: [PATCH 582/828] esp8266/modnetwork: Allow to get ESSID of AP that STA is connected to. This patch enables iface.config('essid') to work for both AP and STA interfaces. --- ports/esp8266/modnetwork.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ports/esp8266/modnetwork.c b/ports/esp8266/modnetwork.c index 00a84c446e..dcc64d40ff 100644 --- a/ports/esp8266/modnetwork.c +++ b/ports/esp8266/modnetwork.c @@ -422,8 +422,11 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs return mp_obj_new_bytes(mac, sizeof(mac)); } case MP_QSTR_essid: - req_if = SOFTAP_IF; - val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len); + if (self->if_id == STATION_IF) { + val = mp_obj_new_str((char*)cfg.sta.ssid, strlen((char*)cfg.sta.ssid)); + } else { + val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len); + } break; case MP_QSTR_hidden: req_if = SOFTAP_IF; From 777e042ab53821b1240466af1e92eceb14c0fdf1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 1 May 2018 16:37:08 +1000 Subject: [PATCH 583/828] esp32/modnetwork: Allow to get ESSID of AP that STA is connected to. Following the same addition to esp8266 port. --- ports/esp32/modnetwork.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index ef5292be3c..f299ec2f03 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -509,8 +509,11 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs return mp_obj_new_bytes(mac, sizeof(mac)); } case QS(MP_QSTR_essid): - req_if = WIFI_IF_AP; - val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len); + if (self->if_id == WIFI_IF_STA) { + val = mp_obj_new_str((char*)cfg.sta.ssid, strlen((char*)cfg.sta.ssid)); + } else { + val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len); + } break; case QS(MP_QSTR_hidden): req_if = WIFI_IF_AP; From a28bd4ac942baec0ddc8da644715b0d6fe386f9f Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 1 May 2018 17:31:23 +1000 Subject: [PATCH 584/828] stm32/mphalport: Add mp_hal_pin_config_speed() to select GPIO speed. It should be used after mp_hal_pin_config() or mp_hal_pin_config_alt(). --- ports/stm32/mphalport.c | 6 ++++++ ports/stm32/mphalport.h | 1 + 2 files changed, 7 insertions(+) diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c index 0108d90261..c822c8e778 100644 --- a/ports/stm32/mphalport.c +++ b/ports/stm32/mphalport.c @@ -171,3 +171,9 @@ bool mp_hal_pin_config_alt(mp_hal_pin_obj_t pin, uint32_t mode, uint32_t pull, u mp_hal_pin_config(pin, mode, pull, af->idx); return true; } + +void mp_hal_pin_config_speed(mp_hal_pin_obj_t pin_obj, uint32_t speed) { + GPIO_TypeDef *gpio = pin_obj->gpio; + uint32_t pin = pin_obj->pin; + gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << (2 * pin))) | (speed << (2 * pin)); +} diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h index 2843a79cd4..0e294a21c4 100644 --- a/ports/stm32/mphalport.h +++ b/ports/stm32/mphalport.h @@ -59,3 +59,4 @@ static inline mp_uint_t mp_hal_ticks_cpu(void) { void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio); void mp_hal_pin_config(mp_hal_pin_obj_t pin, uint32_t mode, uint32_t pull, uint32_t alt); bool mp_hal_pin_config_alt(mp_hal_pin_obj_t pin, uint32_t mode, uint32_t pull, uint8_t fn, uint8_t unit); +void mp_hal_pin_config_speed(mp_hal_pin_obj_t pin_obj, uint32_t speed); From 04ead56614a62c6809e7cf268a4d5936a870ccb8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 1 May 2018 17:32:19 +1000 Subject: [PATCH 585/828] stm32/usbd_conf: Use mp_hal_pin_config() instead of HAL_GPIO_Init. To reduce dependency on the ST HAL for pin operations. --- ports/stm32/usbd_conf.c | 58 ++++++++++++----------------------------- 1 file changed, 17 insertions(+), 41 deletions(-) diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index fe05e2e4c1..d53d369a6c 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -32,6 +32,7 @@ /* Includes ------------------------------------------------------------------*/ #include "usbd_core.h" #include "py/obj.h" +#include "py/mphal.h" #include "irq.h" #include "usb.h" @@ -58,39 +59,28 @@ PCD_HandleTypeDef pcd_hs_handle; */ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { - GPIO_InitTypeDef GPIO_InitStruct; - if(hpcd->Instance == USB_OTG_FS) { - /* Configure USB FS GPIOs */ - __HAL_RCC_GPIOA_CLK_ENABLE(); - - GPIO_InitStruct.Pin = (GPIO_PIN_11 | GPIO_PIN_12); - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; #if defined(STM32H7) - GPIO_InitStruct.Alternate = GPIO_AF10_OTG1_FS; + const uint32_t otg_alt = GPIO_AF10_OTG1_FS; #else - GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS; + const uint32_t otg_alt = GPIO_AF10_OTG_FS; #endif - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + mp_hal_pin_config(pin_A11, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, otg_alt); + mp_hal_pin_config_speed(pin_A11, GPIO_SPEED_FREQ_VERY_HIGH); + mp_hal_pin_config(pin_A12, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, otg_alt); + mp_hal_pin_config_speed(pin_A12, GPIO_SPEED_FREQ_VERY_HIGH); /* Configure VBUS Pin */ #if defined(MICROPY_HW_USB_VBUS_DETECT_PIN) // USB VBUS detect pin is always A9 - GPIO_InitStruct.Pin = GPIO_PIN_9; - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; - GPIO_InitStruct.Pull = GPIO_NOPULL; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + mp_hal_pin_config(MICROPY_HW_USB_VBUS_DETECT_PIN, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0); #endif #if defined(MICROPY_HW_USB_OTG_ID_PIN) // USB ID pin is always A10 - GPIO_InitStruct.Pin = GPIO_PIN_10; - GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; - GPIO_InitStruct.Pull = GPIO_PULLUP; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + mp_hal_pin_config(MICROPY_HW_USB_OTG_ID_PIN, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, otg_alt); #endif #if defined(STM32H7) @@ -128,34 +118,19 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) #if MICROPY_HW_USB_HS_IN_FS /* Configure USB FS GPIOs */ - __HAL_RCC_GPIOB_CLK_ENABLE(); - - /* Configure DM DP Pins */ - GPIO_InitStruct.Pin = (GPIO_PIN_14 | GPIO_PIN_15); - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF12_OTG_HS_FS; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + mp_hal_pin_config(pin_B14, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, GPIO_AF12_OTG_HS_FS); + mp_hal_pin_config_speed(pin_B14, GPIO_SPEED_FREQ_VERY_HIGH); + mp_hal_pin_config(pin_B15, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, GPIO_AF12_OTG_HS_FS); + mp_hal_pin_config_speed(pin_B15, GPIO_SPEED_FREQ_VERY_HIGH); #if defined(MICROPY_HW_USB_VBUS_DETECT_PIN) /* Configure VBUS Pin */ - GPIO_InitStruct.Pin = GPIO_PIN_13; - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF12_OTG_HS_FS; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + mp_hal_pin_config(MICROPY_HW_USB_VBUS_DETECT_PIN, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0); #endif #if defined(MICROPY_HW_USB_OTG_ID_PIN) /* Configure ID pin */ - GPIO_InitStruct.Pin = GPIO_PIN_12; - GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; - GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF12_OTG_HS_FS; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + mp_hal_pin_config(MICROPY_HW_USB_OTG_ID_PIN, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, GPIO_AF12_OTG_HS_FS); #endif /* * Enable calling WFI and correct @@ -176,6 +151,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) __HAL_RCC_USB_OTG_HS_CLK_ENABLE(); #else // !MICROPY_HW_USB_HS_IN_FS + GPIO_InitTypeDef GPIO_InitStruct; /* Configure USB HS GPIOs */ __HAL_RCC_GPIOA_CLK_ENABLE(); From b0ad46cd11f25e4b4d51ad52624fbf6b89c3fff2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 1 May 2018 17:33:08 +1000 Subject: [PATCH 586/828] stm32/dac: Use mp_hal_pin_config() instead of HAL_GPIO_Init(). --- ports/stm32/dac.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c index 5423a2bff7..1b68386412 100644 --- a/ports/stm32/dac.c +++ b/ports/stm32/dac.c @@ -29,6 +29,7 @@ #include #include "py/runtime.h" +#include "py/mphal.h" #include "timer.h" #include "dac.h" #include "dma.h" @@ -144,7 +145,7 @@ typedef struct _pyb_dac_obj_t { mp_obj_base_t base; uint32_t dac_channel; // DAC_CHANNEL_1 or DAC_CHANNEL_2 const dma_descr_t *tx_dma_descr; - uint16_t pin; // GPIO_PIN_4 or GPIO_PIN_5 + mp_hal_pin_obj_t pin; // pin_A4 or pin_A5 uint8_t bits; // 8 or 12 uint8_t state; uint8_t outbuf_single; @@ -162,11 +163,7 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); // GPIO configuration - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.Pin = self->pin; - GPIO_InitStructure.Mode = GPIO_MODE_ANALOG; - GPIO_InitStructure.Pull = GPIO_NOPULL; - HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); + mp_hal_pin_config(self->pin, MP_HAL_PIN_MODE_ANALOG, MP_HAL_PIN_PULL_NONE, 0); // DAC peripheral clock #if defined(STM32F4) || defined(STM32F7) @@ -251,11 +248,11 @@ STATIC mp_obj_t pyb_dac_make_new(const mp_obj_type_t *type, size_t n_args, size_ dac->base.type = &pyb_dac_type; if (dac_id == 1) { - dac->pin = GPIO_PIN_4; + dac->pin = pin_A4; dac->dac_channel = DAC_CHANNEL_1; dac->tx_dma_descr = &dma_DAC_1_TX; } else if (dac_id == 2) { - dac->pin = GPIO_PIN_5; + dac->pin = pin_A5; dac->dac_channel = DAC_CHANNEL_2; dac->tx_dma_descr = &dma_DAC_2_TX; } else { From 68f4cba3d2aa056f305a20c9e394d4ebf81869ce Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 1 May 2018 17:38:51 +1000 Subject: [PATCH 587/828] stm32/boards: Update pins.csv to include USB pins where needed. --- ports/stm32/boards/CERB40/pins.csv | 2 ++ ports/stm32/boards/NETDUINO_PLUS_2/pins.csv | 2 ++ ports/stm32/boards/NUCLEO_F746ZG/pins.csv | 2 +- ports/stm32/boards/NUCLEO_F767ZI/pins.csv | 2 +- ports/stm32/boards/OLIMEX_E407/pins.csv | 3 ++- ports/stm32/boards/PYBV3/pins.csv | 2 ++ ports/stm32/boards/STM32F411DISC/pins.csv | 2 ++ ports/stm32/boards/STM32F4DISC/pins.csv | 3 ++- 8 files changed, 14 insertions(+), 4 deletions(-) diff --git a/ports/stm32/boards/CERB40/pins.csv b/ports/stm32/boards/CERB40/pins.csv index da759f212e..cca0bc0536 100644 --- a/ports/stm32/boards/CERB40/pins.csv +++ b/ports/stm32/boards/CERB40/pins.csv @@ -46,3 +46,5 @@ UART3_RTS,PD12 UART3_CTS,PD11 CAN2_TX,PB13 CAN2_RX,PB12 +USB_DM,PA11 +USB_DP,PA12 diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/pins.csv b/ports/stm32/boards/NETDUINO_PLUS_2/pins.csv index 3e71fade6e..53ffa9d1fe 100644 --- a/ports/stm32/boards/NETDUINO_PLUS_2/pins.csv +++ b/ports/stm32/boards/NETDUINO_PLUS_2/pins.csv @@ -33,3 +33,5 @@ UART3_RX,PD9 UART3_RTS,PD12 UART3_CTS,PD11 UART5_TX,PC12 +USB_DM,PA11 +USB_DP,PA12 diff --git a/ports/stm32/boards/NUCLEO_F746ZG/pins.csv b/ports/stm32/boards/NUCLEO_F746ZG/pins.csv index 897b1473e7..aa5143e8c5 100644 --- a/ports/stm32/boards/NUCLEO_F746ZG/pins.csv +++ b/ports/stm32/boards/NUCLEO_F746ZG/pins.csv @@ -51,7 +51,7 @@ LCD_SCL,PH7 OTG_FS_POWER,PD5 OTG_FS_OVER_CURRENT,PD4 OTG_HS_OVER_CURRENT,PE3 -USB_VBUS,PJ12 +USB_VBUS,PA9 USB_ID,PA10 USB_DM,PA11 USB_DP,PA12 diff --git a/ports/stm32/boards/NUCLEO_F767ZI/pins.csv b/ports/stm32/boards/NUCLEO_F767ZI/pins.csv index 84506649ef..9df4fc7ef7 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/pins.csv +++ b/ports/stm32/boards/NUCLEO_F767ZI/pins.csv @@ -54,7 +54,7 @@ LCD_SCL,PH7 OTG_FS_POWER,PD5 OTG_FS_OVER_CURRENT,PD4 OTG_HS_OVER_CURRENT,PE3 -USB_VBUS,PJ12 +USB_VBUS,PA9 USB_ID,PA10 USB_DM,PA11 USB_DP,PA12 diff --git a/ports/stm32/boards/OLIMEX_E407/pins.csv b/ports/stm32/boards/OLIMEX_E407/pins.csv index 6b91f74ae4..81a9bcb853 100644 --- a/ports/stm32/boards/OLIMEX_E407/pins.csv +++ b/ports/stm32/boards/OLIMEX_E407/pins.csv @@ -82,4 +82,5 @@ PD13,PD13 PD14,PD14 PD15,PD15 PA0,PA0 - +USB_DM,PA11 +USB_DP,PA12 diff --git a/ports/stm32/boards/PYBV3/pins.csv b/ports/stm32/boards/PYBV3/pins.csv index b20bd4ffbd..1ddc3f52da 100644 --- a/ports/stm32/boards/PYBV3/pins.csv +++ b/ports/stm32/boards/PYBV3/pins.csv @@ -44,3 +44,5 @@ SD_D3,PC11 SD_CK,PC12 SD_CMD,PD2 UART1_TX,PA9 +USB_DM,PA11 +USB_DP,PA12 diff --git a/ports/stm32/boards/STM32F411DISC/pins.csv b/ports/stm32/boards/STM32F411DISC/pins.csv index 96077d54d4..a747aef3ef 100644 --- a/ports/stm32/boards/STM32F411DISC/pins.csv +++ b/ports/stm32/boards/STM32F411DISC/pins.csv @@ -82,3 +82,5 @@ LED_ORANGE,PD13 LED_RED,PD14 LED_BLUE,PD15 SW,PA0 +USB_DM,PA11 +USB_DP,PA12 diff --git a/ports/stm32/boards/STM32F4DISC/pins.csv b/ports/stm32/boards/STM32F4DISC/pins.csv index 4049fef7d9..a747aef3ef 100644 --- a/ports/stm32/boards/STM32F4DISC/pins.csv +++ b/ports/stm32/boards/STM32F4DISC/pins.csv @@ -82,4 +82,5 @@ LED_ORANGE,PD13 LED_RED,PD14 LED_BLUE,PD15 SW,PA0 - +USB_DM,PA11 +USB_DP,PA12 From 6b4b6d388be338d36de01b01e25f6e324321750a Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 1 May 2018 23:25:18 +1000 Subject: [PATCH 588/828] py/obj.h: Fix math.e constant for nan-boxing builds. Due to a typo, math.e was too small by around 6e-11. --- py/obj.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/obj.h b/py/obj.h index 80599966e2..95a94836e7 100644 --- a/py/obj.h +++ b/py/obj.h @@ -179,7 +179,7 @@ static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) #define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 1) | 0x0002000000000001)) #if MICROPY_PY_BUILTINS_FLOAT -#define mp_const_float_e {((mp_obj_t)((uint64_t)0x4005bf0a8b125769 + 0x8004000000000000))} +#define mp_const_float_e {((mp_obj_t)((uint64_t)0x4005bf0a8b145769 + 0x8004000000000000))} #define mp_const_float_pi {((mp_obj_t)((uint64_t)0x400921fb54442d18 + 0x8004000000000000))} static inline bool mp_obj_is_float(mp_const_obj_t o) { From 3022947343bc54e09ba144084d391fc83db11f96 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 2 May 2018 12:05:45 +1000 Subject: [PATCH 589/828] stm32/mphalport: Support ADC mode on a pin for L4 MCUs. --- ports/stm32/mphalport.c | 6 ++++++ ports/stm32/mphalport.h | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c index c822c8e778..cf63baab58 100644 --- a/ports/stm32/mphalport.c +++ b/ports/stm32/mphalport.c @@ -157,7 +157,13 @@ void mp_hal_pin_config(mp_hal_pin_obj_t pin_obj, uint32_t mode, uint32_t pull, u uint32_t pin = pin_obj->pin; mp_hal_gpio_clock_enable(gpio); gpio->MODER = (gpio->MODER & ~(3 << (2 * pin))) | ((mode & 3) << (2 * pin)); + #if defined(GPIO_ASCR_ASC0) + // The L4 has a special analog switch to connect the GPIO to the ADC + gpio->OTYPER = (gpio->OTYPER & ~(1 << pin)) | (((mode >> 2) & 1) << pin); + gpio->ASCR = (gpio->ASCR & ~(1 << pin)) | ((mode >> 3) & 1) << pin; + #else gpio->OTYPER = (gpio->OTYPER & ~(1 << pin)) | ((mode >> 2) << pin); + #endif gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << (2 * pin))) | (2 << (2 * pin)); // full speed gpio->PUPDR = (gpio->PUPDR & ~(3 << (2 * pin))) | (pull << (2 * pin)); gpio->AFR[pin >> 3] = (gpio->AFR[pin >> 3] & ~(15 << (4 * (pin & 7)))) | (alt << (4 * (pin & 7))); diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h index 0e294a21c4..511a76cd0c 100644 --- a/ports/stm32/mphalport.h +++ b/ports/stm32/mphalport.h @@ -32,6 +32,11 @@ static inline mp_uint_t mp_hal_ticks_cpu(void) { #define MP_HAL_PIN_MODE_OUTPUT (1) #define MP_HAL_PIN_MODE_ALT (2) #define MP_HAL_PIN_MODE_ANALOG (3) +#if defined(GPIO_ASCR_ASC0) +#define MP_HAL_PIN_MODE_ADC (11) +#else +#define MP_HAL_PIN_MODE_ADC (3) +#endif #define MP_HAL_PIN_MODE_OPEN_DRAIN (5) #define MP_HAL_PIN_MODE_ALT_OPEN_DRAIN (6) #define MP_HAL_PIN_PULL_NONE (GPIO_NOPULL) From d4f8414ebdc5e61ef9127778ab0ce4c09f8839e9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 2 May 2018 12:06:23 +1000 Subject: [PATCH 590/828] stm32/adc: Use mp_hal_pin_config() instead of HAL_GPIO_Init(). This makes ADCAll work correctly on L4 MCUs. --- ports/stm32/adc.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index fdb31ba9c1..297efe5d6f 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -248,21 +248,9 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { } if (ADC_FIRST_GPIO_CHANNEL <= adc_obj->channel && adc_obj->channel <= ADC_LAST_GPIO_CHANNEL) { - // Channels 0-16 correspond to real pins. Configure the GPIO pin in - // ADC mode. - const pin_obj_t *pin = pin_adc1[adc_obj->channel]; - mp_hal_gpio_clock_enable(pin->gpio); - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.Pin = pin->pin_mask; -#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) - GPIO_InitStructure.Mode = GPIO_MODE_ANALOG; -#elif defined(STM32L4) - GPIO_InitStructure.Mode = GPIO_MODE_ANALOG_ADC_CONTROL; -#else - #error Unsupported processor -#endif - GPIO_InitStructure.Pull = GPIO_NOPULL; - HAL_GPIO_Init(pin->gpio, &GPIO_InitStructure); + // Channels 0-16 correspond to real pins. Configure the GPIO pin in ADC mode. + const pin_obj_t *pin = pin_adc1[adc_obj->channel]; + mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0); } adcx_init_periph(&adc_obj->handle, ADC_RESOLUTION_12B); @@ -637,12 +625,7 @@ void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_m // ADC mode. const pin_obj_t *pin = pin_adc1[channel]; if (pin) { - mp_hal_gpio_clock_enable(pin->gpio); - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.Pin = pin->pin_mask; - GPIO_InitStructure.Mode = GPIO_MODE_ANALOG; - GPIO_InitStructure.Pull = GPIO_NOPULL; - HAL_GPIO_Init(pin->gpio, &GPIO_InitStructure); + mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0); } } } From dcfd2de5c2319f026e53c0a63495823a5bb11706 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 2 May 2018 12:07:10 +1000 Subject: [PATCH 591/828] stm32/dac: Make deinit disable the output buffer on H7 and L4 MCUs. --- ports/stm32/dac.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c index 1b68386412..7a72a2106b 100644 --- a/ports/stm32/dac.c +++ b/ports/stm32/dac.c @@ -279,12 +279,16 @@ STATIC mp_obj_t pyb_dac_deinit(mp_obj_t self_in) { pyb_dac_obj_t *self = self_in; if (self->dac_channel == DAC_CHANNEL_1) { DAC_Handle.Instance->CR &= ~DAC_CR_EN1; - #ifndef STM32H7 + #if defined(STM32H7) || defined(STM32L4) + DAC->MCR = (DAC->MCR & ~(7 << DAC_MCR_MODE1_Pos)) | 2 << DAC_MCR_MODE1_Pos; + #else DAC_Handle.Instance->CR |= DAC_CR_BOFF1; #endif } else { DAC_Handle.Instance->CR &= ~DAC_CR_EN2; - #ifndef STM32H7 + #if defined(STM32H7) || defined(STM32L4) + DAC->MCR = (DAC->MCR & ~(7 << DAC_MCR_MODE2_Pos)) | 2 << DAC_MCR_MODE2_Pos; + #else DAC_Handle.Instance->CR |= DAC_CR_BOFF2; #endif } From 00a659f3ee90096cd394927735b42d1a3c9e8059 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 2 May 2018 12:15:31 +1000 Subject: [PATCH 592/828] stm32/dac: Implement printing of a DAC object. --- ports/stm32/dac.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c index 7a72a2106b..0c9e0ae0cf 100644 --- a/ports/stm32/dac.c +++ b/ports/stm32/dac.c @@ -152,6 +152,13 @@ typedef struct _pyb_dac_obj_t { uint8_t outbuf_waveform; } pyb_dac_obj_t; +STATIC void pyb_dac_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_dac_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "DAC(%u, bits=%u)", + self->dac_channel == DAC_CHANNEL_1 ? 1 : 2, + self->bits); +} + STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} }, @@ -529,6 +536,7 @@ STATIC MP_DEFINE_CONST_DICT(pyb_dac_locals_dict, pyb_dac_locals_dict_table); const mp_obj_type_t pyb_dac_type = { { &mp_type_type }, .name = MP_QSTR_DAC, + .print = pyb_dac_print, .make_new = pyb_dac_make_new, .locals_dict = (mp_obj_dict_t*)&pyb_dac_locals_dict, }; From edb600b6a272eeba24c2a656e9486b7afc874327 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 2 May 2018 13:08:58 +1000 Subject: [PATCH 593/828] stm32/mphalport: Optimise the way that GPIO clocks are enabled. --- ports/stm32/mphalport.c | 68 +++++++++++++---------------------------- 1 file changed, 21 insertions(+), 47 deletions(-) diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c index cf63baab58..c55fe76173 100644 --- a/ports/stm32/mphalport.c +++ b/ports/stm32/mphalport.c @@ -100,56 +100,30 @@ void mp_hal_ticks_cpu_enable(void) { } void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) { - if (0) { - #ifdef __HAL_RCC_GPIOA_CLK_ENABLE - } else if (gpio == GPIOA) { - __HAL_RCC_GPIOA_CLK_ENABLE(); - #endif - #ifdef __HAL_RCC_GPIOB_CLK_ENABLE - } else if (gpio == GPIOB) { - __HAL_RCC_GPIOB_CLK_ENABLE(); - #endif - #ifdef __HAL_RCC_GPIOC_CLK_ENABLE - } else if (gpio == GPIOC) { - __HAL_RCC_GPIOC_CLK_ENABLE(); - #endif - #ifdef __HAL_RCC_GPIOD_CLK_ENABLE - } else if (gpio == GPIOD) { - __HAL_RCC_GPIOD_CLK_ENABLE(); - #endif - #ifdef __HAL_RCC_GPIOE_CLK_ENABLE - } else if (gpio == GPIOE) { - __HAL_RCC_GPIOE_CLK_ENABLE(); - #endif - #ifdef __HAL_RCC_GPIOF_CLK_ENABLE - } else if (gpio == GPIOF) { - __HAL_RCC_GPIOF_CLK_ENABLE(); - #endif - #ifdef __HAL_RCC_GPIOG_CLK_ENABLE - } else if (gpio == GPIOG) { - #if defined(STM32L476xx) || defined(STM32L486xx) + #if defined(STM32L476xx) || defined(STM32L486xx) + if (gpio == GPIOG) { // Port G pins 2 thru 15 are powered using VddIO2 on these MCUs. HAL_PWREx_EnableVddIO2(); - #endif - __HAL_RCC_GPIOG_CLK_ENABLE(); - #endif - #ifdef __HAL_RCC_GPIOH_CLK_ENABLE - } else if (gpio == GPIOH) { - __HAL_RCC_GPIOH_CLK_ENABLE(); - #endif - #ifdef __HAL_RCC_GPIOI_CLK_ENABLE - } else if (gpio == GPIOI) { - __HAL_RCC_GPIOI_CLK_ENABLE(); - #endif - #ifdef __HAL_RCC_GPIOJ_CLK_ENABLE - } else if (gpio == GPIOJ) { - __HAL_RCC_GPIOJ_CLK_ENABLE(); - #endif - #ifdef __HAL_RCC_GPIOK_CLK_ENABLE - } else if (gpio == GPIOK) { - __HAL_RCC_GPIOK_CLK_ENABLE(); - #endif } + #endif + + // This logic assumes that all the GPIOx_EN bits are adjacent and ordered in one register + + #if defined(STM32F4) || defined(STM32F7) + #define AHBxENR AHB1ENR + #define AHBxENR_GPIOAEN_Pos RCC_AHB1ENR_GPIOAEN_Pos + #elif defined(STM32H7) + #define AHBxENR AHB4ENR + #define AHBxENR_GPIOAEN_Pos RCC_AHB4ENR_GPIOAEN_Pos + #elif defined(STM32L4) + #define AHBxENR AHB2ENR + #define AHBxENR_GPIOAEN_Pos RCC_AHB2ENR_GPIOAEN_Pos + #endif + + uint32_t gpio_idx = ((uint32_t)gpio - GPIOA_BASE) / (GPIOB_BASE - GPIOA_BASE); + RCC->AHBxENR |= 1 << (AHBxENR_GPIOAEN_Pos + gpio_idx); + volatile uint32_t tmp = RCC->AHBxENR; // Delay after enabling clock + (void)tmp; } void mp_hal_pin_config(mp_hal_pin_obj_t pin_obj, uint32_t mode, uint32_t pull, uint32_t alt) { From 4c0f664b1aaa7b4b3253060799113139f5dfd8cb Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 2 May 2018 13:11:56 +1000 Subject: [PATCH 594/828] stm32/flash: Remove unused src parameter from flash_erase(). --- ports/stm32/flash.c | 4 ++-- ports/stm32/flash.h | 2 +- ports/stm32/flashbdev.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ports/stm32/flash.c b/ports/stm32/flash.c index 214d10fdb0..bc5b3c60c2 100644 --- a/ports/stm32/flash.c +++ b/ports/stm32/flash.c @@ -142,7 +142,7 @@ uint32_t flash_get_sector_info(uint32_t addr, uint32_t *start_addr, uint32_t *si return 0; } -void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) { +void flash_erase(uint32_t flash_dest, uint32_t num_word32) { // check there is something to write if (num_word32 == 0) { return; @@ -192,7 +192,7 @@ void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) /* // erase the sector using an interrupt -void flash_erase_it(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) { +void flash_erase_it(uint32_t flash_dest, uint32_t num_word32) { // check there is something to write if (num_word32 == 0) { return; diff --git a/ports/stm32/flash.h b/ports/stm32/flash.h index d69f6e27f6..b9edf61061 100644 --- a/ports/stm32/flash.h +++ b/ports/stm32/flash.h @@ -27,7 +27,7 @@ #define MICROPY_INCLUDED_STM32_FLASH_H uint32_t flash_get_sector_info(uint32_t addr, uint32_t *start_addr, uint32_t *size); -void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32); +void flash_erase(uint32_t flash_dest, uint32_t num_word32); void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32); #endif // MICROPY_INCLUDED_STM32_FLASH_H diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c index 4245dd1ec5..dc73223348 100644 --- a/ports/stm32/flashbdev.c +++ b/ports/stm32/flashbdev.c @@ -205,7 +205,7 @@ static void flash_bdev_irq_handler(void) { // This code uses interrupts to erase the flash /* if (flash_erase_state == 0) { - flash_erase_it(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4); + flash_erase_it(flash_cache_sector_start, flash_cache_sector_size / 4); flash_erase_state = 1; return; } @@ -223,7 +223,7 @@ static void flash_bdev_irq_handler(void) { // This code erases the flash directly, waiting for it to finish if (!(flash_flags & FLASH_FLAG_ERASED)) { - flash_erase(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4); + flash_erase(flash_cache_sector_start, flash_cache_sector_size / 4); flash_flags |= FLASH_FLAG_ERASED; return; } From 266446624fc055e988782577286fe91efbda438e Mon Sep 17 00:00:00 2001 From: "Peter D. Gray" Date: Fri, 13 Apr 2018 09:14:44 -0400 Subject: [PATCH 595/828] stm32/dma: Always deinit/reinit DMA channels on L4 MCUs. The problem is the existing code which tries to optimise the reinitialisation of the DMA breaks the abstraction of the HAL. For the STM32L4 the HAL's DMA setup code maintains two private vars (ChannelIndex, DmaBaseAddress) and updates a hardware register (CCR). In HAL_DMA_Init(), the CCR is updated to set the direction of the DMA. This is a problem because, when using the SD Card interface, the same DMA channel is used in both directions, so the direction bit in the CCR must follow that. A quick and effective fix for the L4 is to simply call HAL_DMA_DeInit() and HAL_DMA_Init() every time. --- ports/stm32/dma.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index 7ea2eaa3b4..35cfba162e 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -498,6 +498,14 @@ void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void *data){ dma_enable_clock(dma_id); + #if defined(STM32L4) + // Always reset and configure the L4 DMA peripheral + // (dma->State is set to HAL_DMA_STATE_RESET by memset above) + // TODO: understand how L4 DMA works so this is not needed + HAL_DMA_DeInit(dma); + HAL_DMA_Init(dma); + HAL_NVIC_SetPriority(dma_irqn[dma_id], IRQ_PRI_DMA, IRQ_SUBPRI_DMA); + #else // if this stream was previously configured for this channel/request then we // can skip most of the initialisation uint8_t sub_inst = DMA_SUB_INSTANCE_AS_UINT8(dma_descr->sub_instance); @@ -518,6 +526,7 @@ void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void *data){ DMA_CalcBaseAndBitshift(dma); #endif } + #endif HAL_NVIC_EnableIRQ(dma_irqn[dma_id]); } From a03e6c1e05203bb71ebee50af2a41de404b05078 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 2 May 2018 14:41:02 +1000 Subject: [PATCH 596/828] stm32/irq: Define IRQ priorities directly as encoded hardware values. For a given IRQn (eg UART) there's no need to carry around both a PRI and SUBPRI value (eg IRQ_PRI_UART, IRQ_SUBPRI_UART). Instead, the IRQ_PRI_UART value has been changed in this patch to be the encoded hardware value, using NVIC_EncodePriority. This way the NVIC_SetPriority function can be used directly, instead of going through HAL_NVIC_SetPriority which must do extra processing to encode the PRI+SUBPRI. For a priority grouping of 4 (4 bits for preempt priority, 0 bits for the sub-priority), which is used in the stm32 port, the IRQ_PRI_xxx constants remain unchanged in their value. This patch also "fixes" the use of raise_irq_pri() which should be passed the encoded value (but as mentioned above the unencoded value is the same as the encoded value for priority grouping 4, so there was no bug from this error). --- ports/stm32/can.c | 4 ++-- ports/stm32/dma.c | 4 ++-- ports/stm32/extint.c | 4 ++-- ports/stm32/irq.h | 48 ++++++++++++++------------------------ ports/stm32/pendsv.c | 2 +- ports/stm32/rtc.c | 2 +- ports/stm32/sdcard.c | 2 +- ports/stm32/storage.c | 2 +- ports/stm32/system_stm32.c | 2 +- ports/stm32/timer.c | 8 +++---- ports/stm32/uart.c | 2 +- ports/stm32/usbd_conf.c | 4 ++-- 12 files changed, 35 insertions(+), 49 deletions(-) diff --git a/ports/stm32/can.c b/ports/stm32/can.c index ae8e8e27ea..22ac5509c2 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -153,7 +153,7 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { __HAL_CAN_ENABLE_IT(&can_obj->can, CAN_IT_ERR | CAN_IT_BOF | CAN_IT_EPV | CAN_IT_EWG); - HAL_NVIC_SetPriority(sce_irq, IRQ_PRI_CAN, IRQ_SUBPRI_CAN); + NVIC_SetPriority(sce_irq, IRQ_PRI_CAN); HAL_NVIC_EnableIRQ(sce_irq); return true; @@ -934,7 +934,7 @@ STATIC mp_obj_t pyb_can_rxcallback(mp_obj_t self_in, mp_obj_t fifo_in, mp_obj_t irq = (fifo == 0) ? CAN2_RX0_IRQn : CAN2_RX1_IRQn; #endif } - HAL_NVIC_SetPriority(irq, IRQ_PRI_CAN, IRQ_SUBPRI_CAN); + NVIC_SetPriority(irq, IRQ_PRI_CAN); HAL_NVIC_EnableIRQ(irq); __HAL_CAN_ENABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FMP0 : CAN_IT_FMP1); __HAL_CAN_ENABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FF0 : CAN_IT_FF1); diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index 35cfba162e..fde8d678be 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -504,7 +504,7 @@ void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void *data){ // TODO: understand how L4 DMA works so this is not needed HAL_DMA_DeInit(dma); HAL_DMA_Init(dma); - HAL_NVIC_SetPriority(dma_irqn[dma_id], IRQ_PRI_DMA, IRQ_SUBPRI_DMA); + NVIC_SetPriority(IRQn_NONNEG(dma_irqn[dma_id]), IRQ_PRI_DMA); #else // if this stream was previously configured for this channel/request then we // can skip most of the initialisation @@ -516,7 +516,7 @@ void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void *data){ // (dma->State is set to HAL_DMA_STATE_RESET by memset above) HAL_DMA_DeInit(dma); HAL_DMA_Init(dma); - HAL_NVIC_SetPriority(dma_irqn[dma_id], IRQ_PRI_DMA, IRQ_SUBPRI_DMA); + NVIC_SetPriority(IRQn_NONNEG(dma_irqn[dma_id]), IRQ_PRI_DMA); } else { // only necessary initialization dma->State = HAL_DMA_STATE_READY; diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c index 9fe53a1a3c..7c33b317ba 100644 --- a/ports/stm32/extint.c +++ b/ports/stm32/extint.c @@ -214,7 +214,7 @@ uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t ca // Calling HAL_GPIO_Init does an implicit extint_enable /* Enable and set NVIC Interrupt to the lowest priority */ - HAL_NVIC_SetPriority(nvic_irq_channel[v_line], IRQ_PRI_EXTINT, IRQ_SUBPRI_EXTINT); + NVIC_SetPriority(IRQn_NONNEG(nvic_irq_channel[v_line]), IRQ_PRI_EXTINT); HAL_NVIC_EnableIRQ(nvic_irq_channel[v_line]); } return v_line; @@ -270,7 +270,7 @@ void extint_register_pin(const pin_obj_t *pin, uint32_t mode, bool hard_irq, mp_ } // Configure the NVIC - HAL_NVIC_SetPriority(nvic_irq_channel[line], IRQ_PRI_EXTINT, IRQ_SUBPRI_EXTINT); + NVIC_SetPriority(IRQn_NONNEG(nvic_irq_channel[line]), IRQ_PRI_EXTINT); HAL_NVIC_EnableIRQ(nvic_irq_channel[line]); // Enable the interrupt diff --git a/ports/stm32/irq.h b/ports/stm32/irq.h index d0bb49c525..1b68a5488e 100644 --- a/ports/stm32/irq.h +++ b/ports/stm32/irq.h @@ -26,6 +26,10 @@ #ifndef MICROPY_INCLUDED_STM32_IRQ_H #define MICROPY_INCLUDED_STM32_IRQ_H +// Use this macro together with NVIC_SetPriority to indicate that an IRQn is non-negative, +// which helps the compiler optimise the resulting inline function. +#define IRQn_NONNEG(pri) ((pri) & 0x7f) + // these states correspond to values from query_irq, enable_irq and disable_irq #define IRQ_STATE_DISABLED (0x00000001) #define IRQ_STATE_ENABLED (0x00000000) @@ -98,55 +102,37 @@ MP_DECLARE_CONST_FUN_OBJ_0(pyb_irq_stats_obj); // The following interrupts are arranged from highest priority to lowest // priority to make it a bit easier to figure out. -// Priority Sub-Priority -// -------- ------------ -//#def IRQ_PRI_SYSTICK 0 -//#def IRQ_SUBPRI_SYSTICK 0 +//#def IRQ_PRI_SYSTICK NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 0, 0) // The UARTs have no FIFOs, so if they don't get serviced quickly then characters // get dropped. The handling for each character only consumes about 0.5 usec -#define IRQ_PRI_UART 1 -#define IRQ_SUBPRI_UART 0 +#define IRQ_PRI_UART NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 1, 0) // Flash IRQ must be higher priority than interrupts of all those components // that rely on the flash storage. -#define IRQ_PRI_FLASH 2 -#define IRQ_SUBPRI_FLASH 0 +#define IRQ_PRI_FLASH NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 2, 0) // SDIO must be higher priority than DMA for SDIO DMA transfers to work. -#define IRQ_PRI_SDIO 4 -#define IRQ_SUBPRI_SDIO 0 +#define IRQ_PRI_SDIO NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 4, 0) // DMA should be higher priority than USB, since USB Mass Storage calls // into the sdcard driver which waits for the DMA to complete. -#define IRQ_PRI_DMA 5 -#define IRQ_SUBPRI_DMA 0 +#define IRQ_PRI_DMA NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 5, 0) -#define IRQ_PRI_OTG_FS 6 -#define IRQ_SUBPRI_OTG_FS 0 +#define IRQ_PRI_OTG_FS NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0) +#define IRQ_PRI_OTG_HS NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0) +#define IRQ_PRI_TIM5 NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0) -#define IRQ_PRI_OTG_HS 6 -#define IRQ_SUBPRI_OTG_HS 0 - -#define IRQ_PRI_TIM5 6 -#define IRQ_SUBPRI_TIM5 0 - -#define IRQ_PRI_CAN 7 -#define IRQ_SUBPRI_CAN 0 +#define IRQ_PRI_CAN NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 7, 0) // Interrupt priority for non-special timers. -#define IRQ_PRI_TIMX 13 -#define IRQ_SUBPRI_TIMX 0 +#define IRQ_PRI_TIMX NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 13, 0) -#define IRQ_PRI_EXTINT 14 -#define IRQ_SUBPRI_EXTINT 0 +#define IRQ_PRI_EXTINT NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 14, 0) // PENDSV should be at the lowst priority so that other interrupts complete // before exception is raised. -#define IRQ_PRI_PENDSV 15 -#define IRQ_SUBPRI_PENDSV 0 - -#define IRQ_PRI_RTC_WKUP 15 -#define IRQ_SUBPRI_RTC_WKUP 0 +#define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) +#define IRQ_PRI_RTC_WKUP NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) #endif // MICROPY_INCLUDED_STM32_IRQ_H diff --git a/ports/stm32/pendsv.c b/ports/stm32/pendsv.c index 0aeb1a6dcf..b5fe42f70d 100644 --- a/ports/stm32/pendsv.c +++ b/ports/stm32/pendsv.c @@ -40,7 +40,7 @@ void *pendsv_object; void pendsv_init(void) { // set PendSV interrupt at lowest priority - HAL_NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_PENDSV, IRQ_SUBPRI_PENDSV); + NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_PENDSV); } // Call this function to raise a pending exception during an interrupt. diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index 8fb6ae29fc..744fbe8b96 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -656,7 +656,7 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) { EXTI->PR = 1 << 22; #endif - HAL_NVIC_SetPriority(RTC_WKUP_IRQn, IRQ_PRI_RTC_WKUP, IRQ_SUBPRI_RTC_WKUP); + NVIC_SetPriority(RTC_WKUP_IRQn, IRQ_PRI_RTC_WKUP); HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn); //printf("wut=%d wucksel=%d\n", wut, wucksel); diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index 4eb9fce6cd..27e7a34b26 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -173,7 +173,7 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { #endif // NVIC configuration for SDIO interrupts - HAL_NVIC_SetPriority(SDMMC_IRQn, IRQ_PRI_SDIO, IRQ_SUBPRI_SDIO); + NVIC_SetPriority(SDMMC_IRQn, IRQ_PRI_SDIO); HAL_NVIC_EnableIRQ(SDMMC_IRQn); // GPIO have already been initialised by sdcard_init diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index 1450f21565..2ac54a4010 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -55,7 +55,7 @@ void storage_init(void) { // Enable the flash IRQ, which is used to also call our storage IRQ handler // It needs to go at a higher priority than all those components that rely on // the flash storage (eg higher than USB MSC). - HAL_NVIC_SetPriority(FLASH_IRQn, IRQ_PRI_FLASH, IRQ_SUBPRI_FLASH); + NVIC_SetPriority(FLASH_IRQn, IRQ_PRI_FLASH); HAL_NVIC_EnableIRQ(FLASH_IRQn); } } diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c index 6bf9817ccb..2d9f7a15d7 100644 --- a/ports/stm32/system_stm32.c +++ b/ports/stm32/system_stm32.c @@ -599,7 +599,7 @@ void SystemClock_Config(void) HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); - HAL_NVIC_SetPriority(SysTick_IRQn, TICK_INT_PRIORITY, 0); + NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, TICK_INT_PRIORITY, 0)); #endif } diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c index 18661da9c7..c662303c56 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -170,7 +170,7 @@ void timer_tim5_init(void) { __HAL_RCC_TIM5_CLK_ENABLE(); // set up and enable interrupt - HAL_NVIC_SetPriority(TIM5_IRQn, IRQ_PRI_TIM5, IRQ_SUBPRI_TIM5); + NVIC_SetPriority(TIM5_IRQn, IRQ_PRI_TIM5); HAL_NVIC_EnableIRQ(TIM5_IRQn); // PWM clock configuration @@ -611,12 +611,12 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons // set IRQ priority (if not a special timer) if (self->tim_id != 5) { - HAL_NVIC_SetPriority(self->irqn, IRQ_PRI_TIMX, IRQ_SUBPRI_TIMX); + NVIC_SetPriority(IRQn_NONNEG(self->irqn), IRQ_PRI_TIMX); if (self->tim_id == 1) { - HAL_NVIC_SetPriority(TIM1_CC_IRQn, IRQ_PRI_TIMX, IRQ_SUBPRI_TIMX); + NVIC_SetPriority(TIM1_CC_IRQn, IRQ_PRI_TIMX); #if defined(TIM8) } else if (self->tim_id == 8) { - HAL_NVIC_SetPriority(TIM8_CC_IRQn, IRQ_PRI_TIMX, IRQ_SUBPRI_TIMX); + NVIC_SetPriority(TIM8_CC_IRQn, IRQ_PRI_TIMX); #endif } } diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index 677606940e..54dcc05728 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -691,7 +691,7 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const self->read_buf_len = args.read_buf_len.u_int + 1; // +1 to adjust for usable length of buffer self->read_buf = m_new(byte, self->read_buf_len << self->char_width); __HAL_UART_ENABLE_IT(&self->uart, UART_IT_RXNE); - HAL_NVIC_SetPriority(self->irqn, IRQ_PRI_UART, IRQ_SUBPRI_UART); + NVIC_SetPriority(IRQn_NONNEG(self->irqn), IRQ_PRI_UART); HAL_NVIC_EnableIRQ(self->irqn); } diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index d53d369a6c..4902da997d 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -107,7 +107,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) #endif /* Set USBFS Interrupt priority */ - HAL_NVIC_SetPriority(OTG_FS_IRQn, IRQ_PRI_OTG_FS, IRQ_SUBPRI_OTG_FS); + NVIC_SetPriority(OTG_FS_IRQn, IRQ_PRI_OTG_FS); /* Enable USBFS Interrupt */ HAL_NVIC_EnableIRQ(OTG_FS_IRQn); @@ -211,7 +211,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) #endif // !MICROPY_HW_USB_HS_IN_FS /* Set USBHS Interrupt to the lowest priority */ - HAL_NVIC_SetPriority(OTG_HS_IRQn, IRQ_PRI_OTG_HS, IRQ_SUBPRI_OTG_HS); + NVIC_SetPriority(OTG_HS_IRQn, IRQ_PRI_OTG_HS); /* Enable USBHS Interrupt */ HAL_NVIC_EnableIRQ(OTG_HS_IRQn); From 051686b0a84ac78219c3509fda2a81dd89f3428a Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 2 May 2018 15:20:24 +1000 Subject: [PATCH 597/828] stm32/main: Clean up and optimise initial start-up code of the MCU. --- ports/stm32/main.c | 51 +++++++++++++++++++++++++++++++------- ports/stm32/system_stm32.c | 10 -------- 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index eefe47490c..4553a07e28 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2018 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -418,15 +418,48 @@ STATIC uint update_reset_mode(uint reset_mode) { #endif void stm32_main(uint32_t reset_mode) { - // TODO disable JTAG + // Enable caches and prefetch buffers - /* STM32F4xx HAL library initialization: - - Configure the Flash prefetch, instruction and Data caches - - Configure the Systick to generate an interrupt each 1 msec - - Set NVIC Group Priority to 4 - - Global MSP (MCU Support Package) initialization - */ - HAL_Init(); + #if defined(STM32F4) + + #if INSTRUCTION_CACHE_ENABLE + __HAL_FLASH_INSTRUCTION_CACHE_ENABLE(); + #endif + #if DATA_CACHE_ENABLE + __HAL_FLASH_DATA_CACHE_ENABLE(); + #endif + #if PREFETCH_ENABLE + __HAL_FLASH_PREFETCH_BUFFER_ENABLE(); + #endif + + #elif defined(STM32F7) || defined(STM32H7) + + #if ART_ACCLERATOR_ENABLE + __HAL_FLASH_ART_ENABLE(); + #endif + + SCB_EnableICache(); + SCB_EnableDCache(); + + #elif defined(STM32L4) + + #if !INSTRUCTION_CACHE_ENABLE + __HAL_FLASH_INSTRUCTION_CACHE_DISABLE(); + #endif + #if !DATA_CACHE_ENABLE + __HAL_FLASH_DATA_CACHE_DISABLE(); + #endif + #if PREFETCH_ENABLE + __HAL_FLASH_PREFETCH_BUFFER_ENABLE(); + #endif + + #endif + + // Set the priority grouping + NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); + + // SysTick is needed by HAL_RCC_ClockConfig (called in SystemClock_Config) + HAL_InitTick(TICK_INT_PRIORITY); // set the system clock to be HSE SystemClock_Config(); diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c index 2d9f7a15d7..b03a3a357b 100644 --- a/ports/stm32/system_stm32.c +++ b/ports/stm32/system_stm32.c @@ -602,13 +602,3 @@ void SystemClock_Config(void) NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, TICK_INT_PRIORITY, 0)); #endif } - -void HAL_MspInit(void) { -#if defined(STM32F7) || defined(STM32H7) - /* Enable I-Cache */ - SCB_EnableICache(); - - /* Enable D-Cache */ - SCB_EnableDCache(); -#endif -} From db2bdad8a2ed0814a64d0859fa6ea435a110d304 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 2 May 2018 15:25:37 +1000 Subject: [PATCH 598/828] tests/pyb: Update tests to run correctly on PYBv1.0. In adcall.py the pyb module may not be imported, so use ADCAll directly. In dac.py the DAC object now prints more info, so update .exp file. In spi.py the SPI should be deinitialised upon exit, so the test can run a second time correctly. --- tests/pyb/adcall.py | 6 +++--- tests/pyb/dac.py.exp | 2 +- tests/pyb/spi.py | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/pyb/adcall.py b/tests/pyb/adcall.py index afc3033ea8..cfe179a97b 100644 --- a/tests/pyb/adcall.py +++ b/tests/pyb/adcall.py @@ -5,19 +5,19 @@ pins = [Pin.cpu.A0, Pin.cpu.A1, Pin.cpu.A2, Pin.cpu.A3] # set pins to IN mode, init ADCAll, then check pins are ANALOG for p in pins: p.init(p.IN) -adc = pyb.ADCAll(12) +adc = ADCAll(12) for p in pins: print(p) # set pins to IN mode, init ADCAll with mask, then check some pins are ANALOG for p in pins: p.init(p.IN) -adc = pyb.ADCAll(12, 0x70003) +adc = ADCAll(12, 0x70003) for p in pins: print(p) # init all pins to ANALOG -adc = pyb.ADCAll(12) +adc = ADCAll(12) print(adc) # read all channels diff --git a/tests/pyb/dac.py.exp b/tests/pyb/dac.py.exp index ae245f2e61..7ee99652a8 100644 --- a/tests/pyb/dac.py.exp +++ b/tests/pyb/dac.py.exp @@ -1 +1 @@ - +DAC(1, bits=8) diff --git a/tests/pyb/spi.py b/tests/pyb/spi.py index b7a905d78c..88cc975bb6 100644 --- a/tests/pyb/spi.py +++ b/tests/pyb/spi.py @@ -29,3 +29,5 @@ spi.init(SPI.MASTER) spi.send(1, timeout=100) print(spi.recv(1, timeout=100)) print(spi.send_recv(1, timeout=100)) + +spi.deinit() From 6410e174c532395e9309300f550ced0942070040 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 2 May 2018 15:51:19 +1000 Subject: [PATCH 599/828] esp8266: Disable DEBUG_PRINTERS for 512k build. Disabling this saves around 6000 bytes of code space and gets the 512k build fitting in the available flash again (it increased lately due to an increase in the size of the ESP8266 SDK). --- ports/esp8266/main.c | 14 ++++++++++++++ ports/esp8266/mpconfigport_512k.h | 3 +++ 2 files changed, 17 insertions(+) diff --git a/ports/esp8266/main.c b/ports/esp8266/main.c index d1b88a8cec..d2d2c34ece 100644 --- a/ports/esp8266/main.c +++ b/ports/esp8266/main.c @@ -137,3 +137,17 @@ void __assert(const char *file, int line, const char *expr) { for (;;) { } } + +#if !MICROPY_DEBUG_PRINTERS +// With MICROPY_DEBUG_PRINTERS disabled DEBUG_printf is not defined but it +// is still needed by esp-open-lwip for debugging output, so define it here. +#include +int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args); +int DEBUG_printf(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int ret = mp_vprintf(&MICROPY_DEBUG_PRINTER_DEST, fmt, ap); + va_end(ap); + return ret; +} +#endif diff --git a/ports/esp8266/mpconfigport_512k.h b/ports/esp8266/mpconfigport_512k.h index b84c134792..dc97efd35d 100644 --- a/ports/esp8266/mpconfigport_512k.h +++ b/ports/esp8266/mpconfigport_512k.h @@ -5,6 +5,9 @@ #undef MICROPY_EMIT_INLINE_XTENSA #define MICROPY_EMIT_INLINE_XTENSA (0) +#undef MICROPY_DEBUG_PRINTERS +#define MICROPY_DEBUG_PRINTERS (0) + #undef MICROPY_ERROR_REPORTING #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) From 60db80920a1eac962e43991fcffafd16edd11885 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 2 May 2018 16:50:28 +1000 Subject: [PATCH 600/828] py/builtinhelp: Change occurrence of mp_uint_t to size_t. --- py/builtinhelp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/builtinhelp.c b/py/builtinhelp.c index 7106f3cedd..6c2c3b92c0 100644 --- a/py/builtinhelp.c +++ b/py/builtinhelp.c @@ -100,7 +100,7 @@ STATIC void mp_help_print_modules(void) { // print the list of modules in a column-first order #define NUM_COLUMNS (4) #define COLUMN_WIDTH (18) - mp_uint_t len; + size_t len; mp_obj_t *items; mp_obj_list_get(list, &len, &items); unsigned int num_rows = (len + NUM_COLUMNS - 1) / NUM_COLUMNS; From 89b1c4a60cd43697e755b645127387d3b34e6d3f Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 2 May 2018 17:08:48 +1000 Subject: [PATCH 601/828] extmod/vfs: Delegate import_stat to vfs.stat to allow generic FS import. --- extmod/vfs.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/extmod/vfs.c b/extmod/vfs.c index 0585de1c72..16f75aba9a 100644 --- a/extmod/vfs.c +++ b/extmod/vfs.c @@ -130,8 +130,26 @@ mp_import_stat_t mp_vfs_import_stat(const char *path) { return fat_vfs_import_stat(MP_OBJ_TO_PTR(vfs->obj), path_out); } #endif - // TODO delegate to vfs.stat() method - return MP_IMPORT_STAT_NO_EXIST; + + // delegate to vfs.stat() method + mp_obj_t path_o = mp_obj_new_str(path_out, strlen(path_out)); + mp_obj_t stat; + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + stat = mp_vfs_proxy_call(vfs, MP_QSTR_stat, 1, &path_o); + nlr_pop(); + } else { + // assume an exception means that the path is not found + return MP_IMPORT_STAT_NO_EXIST; + } + mp_obj_t *items; + mp_obj_get_array_fixed_n(stat, 10, &items); + mp_int_t st_mode = mp_obj_get_int(items[0]); + if (st_mode & MP_S_IFDIR) { + return MP_IMPORT_STAT_DIR; + } else { + return MP_IMPORT_STAT_FILE; + } } mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { From 5eb198c4419d6620da2d500369bce0343ee2767e Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Tue, 2 Jan 2018 05:55:22 +0100 Subject: [PATCH 602/828] tests/run-tests: Support esp32 as a target for running the test suite. --- tests/run-tests | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-tests b/tests/run-tests index 71eab4905b..82f05bfa84 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -516,7 +516,7 @@ the last matching regex is used: cmd_parser.add_argument('files', nargs='*', help='input test files') args = cmd_parser.parse_args() - EXTERNAL_TARGETS = ('pyboard', 'wipy', 'esp8266', 'minimal') + EXTERNAL_TARGETS = ('pyboard', 'wipy', 'esp8266', 'esp32', 'minimal') if args.target == 'unix' or args.list_tests: pyb = None elif args.target in EXTERNAL_TARGETS: @@ -531,7 +531,7 @@ the last matching regex is used: if args.target == 'pyboard': # run pyboard tests test_dirs = ('basics', 'micropython', 'float', 'misc', 'stress', 'extmod', 'pyb', 'pybnative', 'inlineasm') - elif args.target in ('esp8266', 'minimal'): + elif args.target in ('esp8266', 'esp32', 'minimal'): test_dirs = ('basics', 'micropython', 'float', 'misc', 'extmod') elif args.target == 'wipy': # run WiPy tests From fb7dabb971cdc15aca7e26cbd9cf733fe7b823cf Mon Sep 17 00:00:00 2001 From: Torwag Date: Wed, 3 Jan 2018 15:49:32 +0100 Subject: [PATCH 603/828] esp32/README: Add --init to submodule update command. Add --init to the submodule update example, thus, all submodules get initialised including the nested (--recursive) ones. Without it there might not be a submodule init. --- ports/esp32/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp32/README.md b/ports/esp32/README.md index 16855505fd..25407b834a 100644 --- a/ports/esp32/README.md +++ b/ports/esp32/README.md @@ -32,7 +32,7 @@ git hash of this version can be found by running `make` without a configured $ git clone https://github.com/espressif/esp-idf.git $ git checkout - $ git submodule update --recursive + $ git submodule update --init --recursive The binary toolchain (binutils, gcc, etc.) can be installed using the following guides: From 6681eb809a815a049ca069d522b9ad07548db535 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 2 May 2018 22:31:00 +1000 Subject: [PATCH 604/828] esp32/modsocket: Correctly handle reading from a peer-closed socket. If a socket is cleanly shut down by the peer then reads on this socket should continue to return zero bytes. The lwIP socket API does not have this behaviour (it only returns zero once, then blocks on subsequent calls) so this patch adds explicit checks and logic for peer closed sockets. --- ports/esp32/modsocket.c | 76 ++++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 94cf3cc57c..0268baa18c 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -63,6 +63,7 @@ typedef struct _socket_obj_t { uint8_t domain; uint8_t type; uint8_t proto; + bool peer_closed; unsigned int retries; #if MICROPY_PY_USOCKET_EVENTS mp_obj_t events_callback; @@ -233,6 +234,7 @@ STATIC mp_obj_t socket_accept(const mp_obj_t arg0) { sock->domain = self->domain; sock->type = self->type; sock->proto = self->proto; + sock->peer_closed = false; _socket_settimeout(sock, UINT64_MAX); // make the return value @@ -354,23 +356,57 @@ STATIC mp_obj_t socket_setblocking(const mp_obj_t arg0, const mp_obj_t arg1) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); +// XXX this can end up waiting a very long time if the content is dribbled in one character +// at a time, as the timeout resets each time a recvfrom succeeds ... this is probably not +// good behaviour. +STATIC mp_uint_t _socket_read_data(mp_obj_t self_in, void *buf, size_t size, + struct sockaddr *from, socklen_t *from_len, int *errcode) { + socket_obj_t *sock = MP_OBJ_TO_PTR(self_in); + + // If the peer closed the connection then the lwIP socket API will only return "0" once + // from lwip_recvfrom_r and then block on subsequent calls. To emulate POSIX behaviour, + // which continues to return "0" for each call on a closed socket, we set a flag when + // the peer closed the socket. + if (sock->peer_closed) { + return 0; + } + + // XXX Would be nicer to use RTC to handle timeouts + for (int i = 0; i <= sock->retries; ++i) { + MP_THREAD_GIL_EXIT(); + int r = lwip_recvfrom_r(sock->fd, buf, size, 0, from, from_len); + MP_THREAD_GIL_ENTER(); + if (r == 0) { + sock->peer_closed = true; + } + if (r >= 0) { + return r; + } + if (errno != EWOULDBLOCK) { + *errcode = errno; + return MP_STREAM_ERROR; + } + check_for_exceptions(); + } + + *errcode = sock->retries == 0 ? MP_EWOULDBLOCK : MP_ETIMEDOUT; + return MP_STREAM_ERROR; +} + mp_obj_t _socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in, struct sockaddr *from, socklen_t *from_len) { - socket_obj_t *sock = MP_OBJ_TO_PTR(self_in); size_t len = mp_obj_get_int(len_in); vstr_t vstr; vstr_init_len(&vstr, len); - // XXX Would be nicer to use RTC to handle timeouts - for (int i=0; i<=sock->retries; i++) { - MP_THREAD_GIL_EXIT(); - int r = lwip_recvfrom_r(sock->fd, vstr.buf, len, 0, from, from_len); - MP_THREAD_GIL_ENTER(); - if (r >= 0) { vstr.len = r; return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } - if (errno != EWOULDBLOCK) exception_from_errno(errno); - check_for_exceptions(); + int errcode; + mp_uint_t ret = _socket_read_data(self_in, vstr.buf, len, from, from_len, &errcode); + if (ret == MP_STREAM_ERROR) { + exception_from_errno(errcode); } - mp_raise_OSError(MP_ETIMEDOUT); + + vstr.len = ret; + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) { @@ -468,25 +504,8 @@ STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 3, socket_makefile); - -// XXX this can end up waiting a very long time if the content is dribbled in one character -// at a time, as the timeout resets each time a recvfrom succeeds ... this is probably not -// good behaviour. - STATIC mp_uint_t socket_stream_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { - socket_obj_t *sock = self_in; - - // XXX Would be nicer to use RTC to handle timeouts - for (int i=0; i<=sock->retries; i++) { - MP_THREAD_GIL_EXIT(); - int r = lwip_recvfrom_r(sock->fd, buf, size, 0, NULL, NULL); - MP_THREAD_GIL_ENTER(); - if (r >= 0) return r; - if (r < 0 && errno != EWOULDBLOCK) { *errcode = errno; return MP_STREAM_ERROR; } - check_for_exceptions(); - } - *errcode = sock->retries == 0 ? MP_EWOULDBLOCK : MP_ETIMEDOUT; - return MP_STREAM_ERROR; + return _socket_read_data(self_in, buf, size, NULL, NULL, errcode); } STATIC mp_uint_t socket_stream_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { @@ -592,6 +611,7 @@ STATIC mp_obj_t get_socket(size_t n_args, const mp_obj_t *args) { sock->domain = AF_INET; sock->type = SOCK_STREAM; sock->proto = 0; + sock->peer_closed = false; if (n_args > 0) { sock->domain = mp_obj_get_int(args[0]); if (n_args > 1) { From 4fa7d36cee5dcda836409999612a5022f2d59952 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 2 May 2018 22:33:41 +1000 Subject: [PATCH 605/828] esp32: Use mp_rom_map_elem_t and MP_ROM_xxx macros for const dicts. --- ports/esp32/machine_rtc.c | 8 ++-- ports/esp32/machine_timer.c | 10 ++--- ports/esp32/machine_wdt.c | 4 +- ports/esp32/modnetwork.c | 69 ++++++++++++++-------------------- ports/esp32/modsocket.c | 74 ++++++++++++++++++------------------- 5 files changed, 76 insertions(+), 89 deletions(-) diff --git a/ports/esp32/machine_rtc.c b/ports/esp32/machine_rtc.c index a701344229..b17932da5c 100644 --- a/ports/esp32/machine_rtc.c +++ b/ports/esp32/machine_rtc.c @@ -147,10 +147,10 @@ STATIC mp_obj_t machine_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_memory_obj, 1, 2, machine_rtc_memory); -STATIC const mp_map_elem_t machine_rtc_locals_dict_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&machine_rtc_datetime_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_datetime), (mp_obj_t)&machine_rtc_datetime_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_memory), (mp_obj_t)&machine_rtc_memory_obj }, +STATIC const mp_rom_map_elem_t machine_rtc_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_rtc_datetime_obj) }, + { MP_ROM_QSTR(MP_QSTR_datetime), MP_ROM_PTR(&machine_rtc_datetime_obj) }, + { MP_ROM_QSTR(MP_QSTR_memory), MP_ROM_PTR(&machine_rtc_memory_obj) }, }; STATIC MP_DEFINE_CONST_DICT(machine_rtc_locals_dict, machine_rtc_locals_dict_table); diff --git a/ports/esp32/machine_timer.c b/ports/esp32/machine_timer.c index d75efb8fc1..235a502bd3 100644 --- a/ports/esp32/machine_timer.c +++ b/ports/esp32/machine_timer.c @@ -173,11 +173,11 @@ STATIC mp_obj_t machine_timer_value(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_value_obj, machine_timer_value); -STATIC const mp_map_elem_t machine_timer_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___del__), (mp_obj_t)&machine_timer_deinit_obj }, - { MP_ROM_QSTR(MP_QSTR_deinit), (mp_obj_t)&machine_timer_deinit_obj }, - { MP_ROM_QSTR(MP_QSTR_init), (mp_obj_t)&machine_timer_init_obj }, - { MP_ROM_QSTR(MP_QSTR_value), (mp_obj_t)&machine_timer_value_obj }, +STATIC const mp_rom_map_elem_t machine_timer_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&machine_timer_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_timer_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_timer_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_timer_value_obj) }, { MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(false) }, { MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(true) }, }; diff --git a/ports/esp32/machine_wdt.c b/ports/esp32/machine_wdt.c index f0436056f6..88a58f056a 100644 --- a/ports/esp32/machine_wdt.c +++ b/ports/esp32/machine_wdt.c @@ -65,8 +65,8 @@ STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed); -STATIC const mp_map_elem_t machine_wdt_locals_dict_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR_feed), (mp_obj_t)&machine_wdt_feed_obj }, +STATIC const mp_rom_map_elem_t machine_wdt_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_feed), MP_ROM_PTR(&machine_wdt_feed_obj) }, }; STATIC MP_DEFINE_CONST_DICT(machine_wdt_locals_dict, machine_wdt_locals_dict_table); diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index f299ec2f03..11d50eec32 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -551,15 +551,15 @@ unknown: STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_config_obj, 1, esp_config); -STATIC const mp_map_elem_t wlan_if_locals_dict_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR_active), (mp_obj_t)&esp_active_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&esp_connect_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_disconnect), (mp_obj_t)&esp_disconnect_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_status), (mp_obj_t)&esp_status_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_scan), (mp_obj_t)&esp_scan_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_isconnected), (mp_obj_t)&esp_isconnected_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_config), (mp_obj_t)&esp_config_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ifconfig), (mp_obj_t)&esp_ifconfig_obj }, +STATIC const mp_rom_map_elem_t wlan_if_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&esp_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&esp_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&esp_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&esp_status_obj) }, + { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&esp_scan_obj) }, + { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&esp_isconnected_obj) }, + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&esp_config_obj) }, + { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) }, }; STATIC MP_DEFINE_CONST_DICT(wlan_if_locals_dict, wlan_if_locals_dict_table); @@ -576,43 +576,30 @@ STATIC mp_obj_t esp_phy_mode(size_t n_args, const mp_obj_t *args) { STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_phy_mode_obj, 0, 1, esp_phy_mode); -STATIC const mp_map_elem_t mp_module_network_globals_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_network) }, - { MP_OBJ_NEW_QSTR(MP_QSTR___init__), (mp_obj_t)&esp_initialize_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_WLAN), (mp_obj_t)&get_wlan_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_LAN), (mp_obj_t)&get_lan_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_phy_mode), (mp_obj_t)&esp_phy_mode_obj }, +STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) }, + { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&esp_initialize_obj) }, + { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&get_wlan_obj) }, + { MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&get_lan_obj) }, + { MP_ROM_QSTR(MP_QSTR_phy_mode), MP_ROM_PTR(&esp_phy_mode_obj) }, #if MODNETWORK_INCLUDE_CONSTANTS - { MP_OBJ_NEW_QSTR(MP_QSTR_STA_IF), - MP_OBJ_NEW_SMALL_INT(WIFI_IF_STA)}, - { MP_OBJ_NEW_QSTR(MP_QSTR_AP_IF), - MP_OBJ_NEW_SMALL_INT(WIFI_IF_AP)}, + { MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(WIFI_IF_STA)}, + { MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(WIFI_IF_AP)}, - { MP_OBJ_NEW_QSTR(MP_QSTR_MODE_11B), - MP_OBJ_NEW_SMALL_INT(WIFI_PROTOCOL_11B) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_MODE_11G), - MP_OBJ_NEW_SMALL_INT(WIFI_PROTOCOL_11G) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_MODE_11N), - MP_OBJ_NEW_SMALL_INT(WIFI_PROTOCOL_11N) }, + { MP_ROM_QSTR(MP_QSTR_MODE_11B), MP_ROM_INT(WIFI_PROTOCOL_11B) }, + { MP_ROM_QSTR(MP_QSTR_MODE_11G), MP_ROM_INT(WIFI_PROTOCOL_11G) }, + { MP_ROM_QSTR(MP_QSTR_MODE_11N), MP_ROM_INT(WIFI_PROTOCOL_11N) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_AUTH_OPEN), - MP_OBJ_NEW_SMALL_INT(WIFI_AUTH_OPEN) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_AUTH_WEP), - MP_OBJ_NEW_SMALL_INT(WIFI_AUTH_WEP) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_AUTH_WPA_PSK), - MP_OBJ_NEW_SMALL_INT(WIFI_AUTH_WPA_PSK) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_AUTH_WPA2_PSK), - MP_OBJ_NEW_SMALL_INT(WIFI_AUTH_WPA2_PSK) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_AUTH_WPA_WPA2_PSK), - MP_OBJ_NEW_SMALL_INT(WIFI_AUTH_WPA_WPA2_PSK) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_AUTH_MAX), - MP_OBJ_NEW_SMALL_INT(WIFI_AUTH_MAX) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_OPEN), MP_ROM_INT(WIFI_AUTH_OPEN) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_WEP), MP_ROM_INT(WIFI_AUTH_WEP) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_PSK), MP_ROM_INT(WIFI_AUTH_WPA_PSK) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_PSK), MP_ROM_INT(WIFI_AUTH_WPA2_PSK) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_WPA2_PSK), MP_ROM_INT(WIFI_AUTH_WPA_WPA2_PSK) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_MAX), MP_ROM_INT(WIFI_AUTH_MAX) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_PHY_LAN8720), - MP_OBJ_NEW_SMALL_INT(PHY_LAN8720) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_PHY_TLK110), - MP_OBJ_NEW_SMALL_INT(PHY_TLK110) }, + { MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(PHY_LAN8720) }, + { MP_ROM_QSTR(MP_QSTR_PHY_TLK110), MP_ROM_INT(PHY_TLK110) }, #endif }; diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 0268baa18c..1bac4432f2 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -567,28 +567,28 @@ STATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintpt return MP_STREAM_ERROR; } -STATIC const mp_map_elem_t socket_locals_dict_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&mp_stream_close_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&mp_stream_close_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_bind), (mp_obj_t)&socket_bind_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_listen), (mp_obj_t)&socket_listen_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_accept), (mp_obj_t)&socket_accept_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&socket_connect_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&socket_send_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sendall), (mp_obj_t)&socket_sendall_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sendto), (mp_obj_t)&socket_sendto_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&socket_recv_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_recvfrom), (mp_obj_t)&socket_recvfrom_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_setsockopt), (mp_obj_t)&socket_setsockopt_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_settimeout), (mp_obj_t)&socket_settimeout_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_setblocking), (mp_obj_t)&socket_setblocking_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_makefile), (mp_obj_t)&socket_makefile_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_fileno), (mp_obj_t)&socket_fileno_obj }, +STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) }, + { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) }, + { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socket_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_sendall), MP_ROM_PTR(&socket_sendall_obj) }, + { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&socket_recv_obj) }, + { MP_ROM_QSTR(MP_QSTR_recvfrom), MP_ROM_PTR(&socket_recvfrom_obj) }, + { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) }, + { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socket_settimeout_obj) }, + { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, + { MP_ROM_QSTR(MP_QSTR_makefile), MP_ROM_PTR(&socket_makefile_obj) }, + { MP_ROM_QSTR(MP_QSTR_fileno), MP_ROM_PTR(&socket_fileno_obj) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&mp_stream_readinto_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj}, - { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, }; STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table); @@ -679,23 +679,23 @@ STATIC mp_obj_t esp_socket_initialize() { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_socket_initialize_obj, esp_socket_initialize); -STATIC const mp_map_elem_t mp_module_socket_globals_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_usocket) }, - { MP_OBJ_NEW_QSTR(MP_QSTR___init__), (mp_obj_t)&esp_socket_initialize_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&get_socket_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_getaddrinfo), (mp_obj_t)&esp_socket_getaddrinfo_obj }, +STATIC const mp_rom_map_elem_t mp_module_socket_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usocket) }, + { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&esp_socket_initialize_obj) }, + { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&get_socket_obj) }, + { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&esp_socket_getaddrinfo_obj) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET), MP_OBJ_NEW_SMALL_INT(AF_INET) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET6), MP_OBJ_NEW_SMALL_INT(AF_INET6) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_STREAM), MP_OBJ_NEW_SMALL_INT(SOCK_STREAM) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_DGRAM), MP_OBJ_NEW_SMALL_INT(SOCK_DGRAM) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_RAW), MP_OBJ_NEW_SMALL_INT(SOCK_RAW) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_TCP), MP_OBJ_NEW_SMALL_INT(IPPROTO_TCP) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_UDP), MP_OBJ_NEW_SMALL_INT(IPPROTO_UDP) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_IP), MP_OBJ_NEW_SMALL_INT(IPPROTO_IP) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SOL_SOCKET), MP_OBJ_NEW_SMALL_INT(SOL_SOCKET) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SO_REUSEADDR), MP_OBJ_NEW_SMALL_INT(SO_REUSEADDR) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_IP_ADD_MEMBERSHIP), MP_OBJ_NEW_SMALL_INT(IP_ADD_MEMBERSHIP) }, + { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(AF_INET) }, + { MP_ROM_QSTR(MP_QSTR_AF_INET6), MP_ROM_INT(AF_INET6) }, + { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(SOCK_STREAM) }, + { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(SOCK_DGRAM) }, + { MP_ROM_QSTR(MP_QSTR_SOCK_RAW), MP_ROM_INT(SOCK_RAW) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_TCP), MP_ROM_INT(IPPROTO_TCP) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_UDP), MP_ROM_INT(IPPROTO_UDP) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_IP), MP_ROM_INT(IPPROTO_IP) }, + { MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(SOL_SOCKET) }, + { MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(SO_REUSEADDR) }, + { MP_ROM_QSTR(MP_QSTR_IP_ADD_MEMBERSHIP), MP_ROM_INT(IP_ADD_MEMBERSHIP) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_socket_globals, mp_module_socket_globals_table); From 59361681501cda2aa998fda649929591308aaebb Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 2 May 2018 23:16:22 +1000 Subject: [PATCH 606/828] extmod/uzlib: Fix C-language sequencing error with uzlib_get_byte calls. The order of function calls in an arithmetic expression is undefined and so they must be written out as sequential statements. Thanks to @dv-extrarius for reporting this issue, see issue #3690. --- extmod/uzlib/tinflate.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/extmod/uzlib/tinflate.c b/extmod/uzlib/tinflate.c index 58850eb4a2..21558af5bf 100644 --- a/extmod/uzlib/tinflate.c +++ b/extmod/uzlib/tinflate.c @@ -394,9 +394,11 @@ static int tinf_inflate_uncompressed_block(TINF_DATA *d) unsigned int length, invlength; /* get length */ - length = uzlib_get_byte(d) + 256 * uzlib_get_byte(d); + length = uzlib_get_byte(d); + length += 256 * uzlib_get_byte(d); /* get one's complement of length */ - invlength = uzlib_get_byte(d) + 256 * uzlib_get_byte(d); + invlength = uzlib_get_byte(d); + invlength += 256 * uzlib_get_byte(d); /* check length */ if (length != (~invlength & 0x0000ffff)) return TINF_DATA_ERROR; From 12a3fccc7e07124afd8634353baa2a2a32a04c8d Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 3 May 2018 00:09:25 +1000 Subject: [PATCH 607/828] esp32/modsocket: Check for pending events during blocking socket calls. --- ports/esp32/modsocket.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 1bac4432f2..daa77f581c 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -146,12 +146,8 @@ NORETURN static void exception_from_errno(int _errno) { mp_raise_OSError(_errno); } -void check_for_exceptions() { - mp_obj_t exc = MP_STATE_VM(mp_pending_exception); - if (exc != MP_OBJ_NULL) { - MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; - nlr_raise(exc); - } +static inline void check_for_exceptions(void) { + mp_handle_pending(); } static int _socket_getaddrinfo2(const mp_obj_t host, const mp_obj_t portx, struct addrinfo **resp) { From 318f874cda22567a55bb004434ed0ec891fd7d61 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 4 May 2018 15:15:04 +1000 Subject: [PATCH 608/828] extmod/modlwip: In ioctl handle case when socket is in an error state. Using MP_STREAM_POLL_HUP for ERR_RST state follows how *nix handles this case. --- extmod/modlwip.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index b23f53961a..3aa0237073 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -1132,7 +1132,8 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ ret |= MP_STREAM_POLL_RD; } - if (flags & MP_STREAM_POLL_WR && tcp_sndbuf(socket->pcb.tcp) > 0) { + // Note: pcb.tcp==NULL if state<0, and in this case we can't call tcp_sndbuf + if (flags & MP_STREAM_POLL_WR && socket->pcb.tcp != NULL && tcp_sndbuf(socket->pcb.tcp) > 0) { ret |= MP_STREAM_POLL_WR; } @@ -1141,6 +1142,13 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ // return EOF, write - error. Without this poll will hang on a // socket which was closed by peer. ret |= flags & (MP_STREAM_POLL_RD | MP_STREAM_POLL_WR); + } else if (socket->state == ERR_RST) { + // Socket was reset by peer, a write will return an error + ret |= flags & (MP_STREAM_POLL_WR | MP_STREAM_POLL_HUP); + } else if (socket->state < 0) { + // Socket in some other error state, use catch-all ERR flag + // TODO: may need to set other return flags here + ret |= flags & MP_STREAM_POLL_ERR; } } else if (request == MP_STREAM_CLOSE) { From b614dc73b085c803f465f1c920553e13f52aee00 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 4 May 2018 15:35:43 +1000 Subject: [PATCH 609/828] stm32/dma: Fix duplicate typedef of struct, it's typedef'd in dma.h. --- ports/stm32/dma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index fde8d678be..499649b36d 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -52,7 +52,7 @@ typedef enum { dma_id_15, } dma_id_t; -typedef struct _dma_descr_t { +struct _dma_descr_t { #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) DMA_Stream_TypeDef *instance; #elif defined(STM32L4) @@ -64,7 +64,7 @@ typedef struct _dma_descr_t { uint32_t transfer_direction; // periph to memory or vice-versa dma_id_t id; const DMA_InitTypeDef *init; -} dma_descr_t; +}; // Default parameters to dma_init() shared by spi and i2c; Channel and Direction // vary depending on the peripheral instance so they get passed separately From cb3456ddfe330c562b7d7dde64df933ab7d987f1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 4 May 2018 15:52:03 +1000 Subject: [PATCH 610/828] stm32: Don't use %lu or %lx for formatting, use just %u or %x. On this 32-bit arch there's no need to use the long version of the format specifier. It's only there to appease the compiler which checks the type of the args passed to printf. Removing the "l" saves a bit of code space. --- ports/stm32/adc.c | 2 +- ports/stm32/extint.c | 74 ++++++++++++++++++++-------------------- ports/stm32/led.c | 2 +- ports/stm32/modmachine.c | 10 +++--- ports/stm32/pyb_i2c.c | 2 +- ports/stm32/servo.c | 2 +- ports/stm32/timer.c | 2 +- 7 files changed, 47 insertions(+), 47 deletions(-) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 297efe5d6f..efc89a7780 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -310,7 +310,7 @@ STATIC void adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t pyb_obj_adc_t *self = self_in; mp_print_str(print, "pin_name, PRINT_STR); - mp_printf(print, " channel=%lu>", self->channel); + mp_printf(print, " channel=%u>", self->channel); } /// \classmethod \constructor(pin) diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c index 7c33b317ba..844cfb0622 100644 --- a/ports/stm32/extint.c +++ b/ports/stm32/extint.c @@ -387,44 +387,44 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_swint_obj, extint_obj_swint); /// Dump the values of the EXTI registers. STATIC mp_obj_t extint_regs(void) { #if defined(STM32L4) - printf("EXTI_IMR1 %08lx\n", EXTI->IMR1); - printf("EXTI_IMR2 %08lx\n", EXTI->IMR2); - printf("EXTI_EMR1 %08lx\n", EXTI->EMR1); - printf("EXTI_EMR2 %08lx\n", EXTI->EMR2); - printf("EXTI_RTSR1 %08lx\n", EXTI->RTSR1); - printf("EXTI_RTSR2 %08lx\n", EXTI->RTSR2); - printf("EXTI_FTSR1 %08lx\n", EXTI->FTSR1); - printf("EXTI_FTSR2 %08lx\n", EXTI->FTSR2); - printf("EXTI_SWIER1 %08lx\n", EXTI->SWIER1); - printf("EXTI_SWIER2 %08lx\n", EXTI->SWIER2); - printf("EXTI_PR1 %08lx\n", EXTI->PR1); - printf("EXTI_PR2 %08lx\n", EXTI->PR2); + printf("EXTI_IMR1 %08x\n", (unsigned int)EXTI->IMR1); + printf("EXTI_IMR2 %08x\n", (unsigned int)EXTI->IMR2); + printf("EXTI_EMR1 %08x\n", (unsigned int)EXTI->EMR1); + printf("EXTI_EMR2 %08x\n", (unsigned int)EXTI->EMR2); + printf("EXTI_RTSR1 %08x\n", (unsigned int)EXTI->RTSR1); + printf("EXTI_RTSR2 %08x\n", (unsigned int)EXTI->RTSR2); + printf("EXTI_FTSR1 %08x\n", (unsigned int)EXTI->FTSR1); + printf("EXTI_FTSR2 %08x\n", (unsigned int)EXTI->FTSR2); + printf("EXTI_SWIER1 %08x\n", (unsigned int)EXTI->SWIER1); + printf("EXTI_SWIER2 %08x\n", (unsigned int)EXTI->SWIER2); + printf("EXTI_PR1 %08x\n", (unsigned int)EXTI->PR1); + printf("EXTI_PR2 %08x\n", (unsigned int)EXTI->PR2); #elif defined(STM32H7) - printf("EXTI_IMR1 %08lx\n", EXTI_D1->IMR1); - printf("EXTI_IMR2 %08lx\n", EXTI_D1->IMR2); - printf("EXTI_IMR3 %08lx\n", EXTI_D1->IMR3); - printf("EXTI_EMR1 %08lx\n", EXTI_D1->EMR1); - printf("EXTI_EMR2 %08lx\n", EXTI_D1->EMR2); - printf("EXTI_EMR3 %08lx\n", EXTI_D1->EMR3); - printf("EXTI_RTSR1 %08lx\n", EXTI->RTSR1); - printf("EXTI_RTSR2 %08lx\n", EXTI->RTSR2); - printf("EXTI_RTSR3 %08lx\n", EXTI->RTSR3); - printf("EXTI_FTSR1 %08lx\n", EXTI->FTSR1); - printf("EXTI_FTSR2 %08lx\n", EXTI->FTSR2); - printf("EXTI_FTSR3 %08lx\n", EXTI->FTSR3); - printf("EXTI_SWIER1 %08lx\n", EXTI->SWIER1); - printf("EXTI_SWIER2 %08lx\n", EXTI->SWIER2); - printf("EXTI_SWIER3 %08lx\n", EXTI->SWIER3); - printf("EXTI_PR1 %08lx\n", EXTI_D1->PR1); - printf("EXTI_PR2 %08lx\n", EXTI_D1->PR2); - printf("EXTI_PR3 %08lx\n", EXTI_D1->PR3); + printf("EXTI_IMR1 %08x\n", (unsigned int)EXTI_D1->IMR1); + printf("EXTI_IMR2 %08x\n", (unsigned int)EXTI_D1->IMR2); + printf("EXTI_IMR3 %08x\n", (unsigned int)EXTI_D1->IMR3); + printf("EXTI_EMR1 %08x\n", (unsigned int)EXTI_D1->EMR1); + printf("EXTI_EMR2 %08x\n", (unsigned int)EXTI_D1->EMR2); + printf("EXTI_EMR3 %08x\n", (unsigned int)EXTI_D1->EMR3); + printf("EXTI_RTSR1 %08x\n", (unsigned int)EXTI->RTSR1); + printf("EXTI_RTSR2 %08x\n", (unsigned int)EXTI->RTSR2); + printf("EXTI_RTSR3 %08x\n", (unsigned int)EXTI->RTSR3); + printf("EXTI_FTSR1 %08x\n", (unsigned int)EXTI->FTSR1); + printf("EXTI_FTSR2 %08x\n", (unsigned int)EXTI->FTSR2); + printf("EXTI_FTSR3 %08x\n", (unsigned int)EXTI->FTSR3); + printf("EXTI_SWIER1 %08x\n", (unsigned int)EXTI->SWIER1); + printf("EXTI_SWIER2 %08x\n", (unsigned int)EXTI->SWIER2); + printf("EXTI_SWIER3 %08x\n", (unsigned int)EXTI->SWIER3); + printf("EXTI_PR1 %08x\n", (unsigned int)EXTI_D1->PR1); + printf("EXTI_PR2 %08x\n", (unsigned int)EXTI_D1->PR2); + printf("EXTI_PR3 %08x\n", (unsigned int)EXTI_D1->PR3); #else - printf("EXTI_IMR %08lx\n", EXTI->IMR); - printf("EXTI_EMR %08lx\n", EXTI->EMR); - printf("EXTI_RTSR %08lx\n", EXTI->RTSR); - printf("EXTI_FTSR %08lx\n", EXTI->FTSR); - printf("EXTI_SWIER %08lx\n", EXTI->SWIER); - printf("EXTI_PR %08lx\n", EXTI->PR); + printf("EXTI_IMR %08x\n", (unsigned int)EXTI->IMR); + printf("EXTI_EMR %08x\n", (unsigned int)EXTI->EMR); + printf("EXTI_RTSR %08x\n", (unsigned int)EXTI->RTSR); + printf("EXTI_FTSR %08x\n", (unsigned int)EXTI->FTSR); + printf("EXTI_SWIER %08x\n", (unsigned int)EXTI->SWIER); + printf("EXTI_PR %08x\n", (unsigned int)EXTI->PR); #endif return mp_const_none; } @@ -534,7 +534,7 @@ void Handle_EXTI_Irq(uint32_t line) { // Uncaught exception; disable the callback so it doesn't run again. *cb = mp_const_none; extint_disable(line); - printf("Uncaught exception in ExtInt interrupt handler line %lu\n", line); + printf("Uncaught exception in ExtInt interrupt handler line %u\n", (unsigned int)line); mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); } gc_unlock(); diff --git a/ports/stm32/led.c b/ports/stm32/led.c index 6586f92131..71c674ab96 100644 --- a/ports/stm32/led.c +++ b/ports/stm32/led.c @@ -281,7 +281,7 @@ void led_debug(int n, int delay) { void led_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { pyb_led_obj_t *self = self_in; - mp_printf(print, "LED(%lu)", self->led_id); + mp_printf(print, "LED(%u)", self->led_id); } /// \classmethod \constructor(id) diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index 6b7849bb9b..73442719b5 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -140,11 +140,11 @@ STATIC mp_obj_t machine_info(size_t n_args, const mp_obj_t *args) { // get and print clock speeds // SYSCLK=168MHz, HCLK=168MHz, PCLK1=42MHz, PCLK2=84MHz { - printf("S=%lu\nH=%lu\nP1=%lu\nP2=%lu\n", - HAL_RCC_GetSysClockFreq(), - HAL_RCC_GetHCLKFreq(), - HAL_RCC_GetPCLK1Freq(), - HAL_RCC_GetPCLK2Freq()); + printf("S=%u\nH=%u\nP1=%u\nP2=%u\n", + (unsigned int)HAL_RCC_GetSysClockFreq(), + (unsigned int)HAL_RCC_GetHCLKFreq(), + (unsigned int)HAL_RCC_GetPCLK1Freq(), + (unsigned int)HAL_RCC_GetPCLK2Freq()); } // to print info about memory diff --git a/ports/stm32/pyb_i2c.c b/ports/stm32/pyb_i2c.c index 1b77ea0bef..db09f688bf 100644 --- a/ports/stm32/pyb_i2c.c +++ b/ports/stm32/pyb_i2c.c @@ -198,7 +198,7 @@ STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) { } } nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "Unsupported I2C baudrate: %lu", baudrate)); + "Unsupported I2C baudrate: %u", baudrate)); } uint32_t pyb_i2c_get_baudrate(I2C_HandleTypeDef *i2c) { diff --git a/ports/stm32/servo.c b/ports/stm32/servo.c index 966d2c688e..dc92872ebd 100644 --- a/ports/stm32/servo.c +++ b/ports/stm32/servo.c @@ -176,7 +176,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(pyb_pwm_set_obj, pyb_pwm_set); STATIC void pyb_servo_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { pyb_servo_obj_t *self = self_in; - mp_printf(print, "", self - &pyb_servo_obj[0] + 1, 10 * self->pulse_cur); + mp_printf(print, "", self - &pyb_servo_obj[0] + 1, 10 * self->pulse_cur); } /// \classmethod \constructor(id) diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c index c662303c56..b220bec5ff 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -1459,7 +1459,7 @@ void timer_irq_handler(uint tim_id) { if (unhandled != 0) { __HAL_TIM_DISABLE_IT(&tim->tim, unhandled); __HAL_TIM_CLEAR_IT(&tim->tim, unhandled); - printf("Unhandled interrupt SR=0x%02lx (now disabled)\n", unhandled); + printf("Unhandled interrupt SR=0x%02x (now disabled)\n", (unsigned int)unhandled); } } } From aea71dbde0d7bc31d9ac40ee1905c884fbf7b0de Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 4 May 2018 15:53:51 +1000 Subject: [PATCH 611/828] stm32/Makefile: Use -O2 to optimise compilation of lib/libc/string0.c. --- ports/stm32/Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 7daf4df4a9..99e2995ffb 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -350,6 +350,11 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_USBDEV:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) OBJ += $(BUILD)/pins_$(BOARD).o +# This file contains performance critical functions so turn up the optimisation +# level. It doesn't add much to the code size and improves performance a bit. +# Don't use -O3 with this file because gcc tries to optimise memset in terms of itself. +$(BUILD)/lib/libc/string0.o: COPT += -O2 + # We put several files into the first 16K section with the ISRs. # If we compile these using -O0 then it won't fit. So if you really want these # to be compiled with -O0, then edit boards/common.ld (in the .isr_vector section) From 3cf02be4e025ae74fa1a6924ff773e40fe5ef970 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 4 May 2018 20:39:16 +1000 Subject: [PATCH 612/828] py/emitnx86: Fix 32-bit x86 native emitter build by including header. --- py/emitnx86.c | 1 + 1 file changed, 1 insertion(+) diff --git a/py/emitnx86.c b/py/emitnx86.c index d4cd24d74f..5d2bbb267a 100644 --- a/py/emitnx86.c +++ b/py/emitnx86.c @@ -1,6 +1,7 @@ // x86 specific stuff #include "py/mpconfig.h" +#include "py/runtime0.h" #if MICROPY_EMIT_X86 From 4b5111f8e1ec1fc0dc0845a090beee1ecbd309df Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 4 May 2018 22:19:50 +1000 Subject: [PATCH 613/828] tests/cpydiff: Remove core_function_unpacking now that it succeeds. Commit 1e70fda69fcb4991eb60ed43e610f664ea1319e6 fixes this difference. --- tests/cpydiff/core_function_unpacking.py | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 tests/cpydiff/core_function_unpacking.py diff --git a/tests/cpydiff/core_function_unpacking.py b/tests/cpydiff/core_function_unpacking.py deleted file mode 100644 index 01d25ee4d2..0000000000 --- a/tests/cpydiff/core_function_unpacking.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -categories: Core,Functions -description: Unpacking function arguments in non-last position isn't detected as an error -cause: Unknown -workaround: The syntax below is invalid, never use it in applications. -""" -print(*(1, 2), 3) From cd9d71edc819615a72e01d3ddd602e9bd4c99803 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 4 May 2018 22:27:14 +1000 Subject: [PATCH 614/828] tests/cpydiff: Remove types_str_decodeerror now that it succeeds. Commit 68c28174d0e0ec3f6b1461aea3a0b6a1b84610bb implemented checking for valid utf-8 data. --- tests/cpydiff/types_str_decodeerror.py | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 tests/cpydiff/types_str_decodeerror.py diff --git a/tests/cpydiff/types_str_decodeerror.py b/tests/cpydiff/types_str_decodeerror.py deleted file mode 100644 index 944db98fe2..0000000000 --- a/tests/cpydiff/types_str_decodeerror.py +++ /dev/null @@ -1,11 +0,0 @@ -""" -categories: Types,str -description: UnicodeDecodeError not raised when expected -cause: Unknown -workaround: Unknown -""" -try: - print(repr(str(b"\xa1\x80", 'utf8'))) - print('Should not get here') -except UnicodeDecodeError: - print('UnicodeDecodeError') From 74ab341d3a1bf3fa5979d8aa5bd390ac0bb319a1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 4 May 2018 22:30:50 +1000 Subject: [PATCH 615/828] tests/cpydiff: Remove working cases from types_float_rounding. --- tests/cpydiff/types_float_rounding.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/cpydiff/types_float_rounding.py b/tests/cpydiff/types_float_rounding.py index 82a149d859..c8d3cfbe88 100644 --- a/tests/cpydiff/types_float_rounding.py +++ b/tests/cpydiff/types_float_rounding.py @@ -5,5 +5,3 @@ cause: Unknown workaround: Unknown """ print('%.1g' % -9.9) -print('%.1e' % 9.99) -print('%.1e' % 0.999) From 2ada1124d42a85e056637fc10c0c2764ba96bdd6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 8 May 2018 17:05:32 +1000 Subject: [PATCH 616/828] tests/cpydiff: Remove types_int_tobytesfloat now that it doesn't fail. Commit e269cabe3ed8bed1b7181359febb686edbb748ae added a check that the first argument to the to_bytes() method is an integer, and now uPy follows CPython behaviour and raises a TypeError for this test. Note: CPython checks the argument types before checking the number of arguments, but uPy does it the other way around, so they give different exception messages for this test, but still the same type, a TypeError. --- tests/cpydiff/types_int_tobytesfloat.py | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 tests/cpydiff/types_int_tobytesfloat.py diff --git a/tests/cpydiff/types_int_tobytesfloat.py b/tests/cpydiff/types_int_tobytesfloat.py deleted file mode 100644 index 5d5b980fad..0000000000 --- a/tests/cpydiff/types_int_tobytesfloat.py +++ /dev/null @@ -1,10 +0,0 @@ -""" -categories: Types,int -description: Incorrect error message when passing float into to_bytes -cause: Unknown -workaround: Unknown -""" -try: - int('1').to_bytes(1.0) -except TypeError as e: - print(e) From e638defff453102d5d0811f7b9a596682a21e9af Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 9 May 2018 15:53:09 +1000 Subject: [PATCH 617/828] stm32/i2c: Make sure stop condition is sent after receiving addr nack. --- ports/stm32/i2c.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index 7421ae1bd2..63bd09ae5f 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -113,7 +113,8 @@ int i2c_start_addr(i2c_t *i2c, int rd_wrn, uint16_t addr, size_t len, bool stop) // Check if the slave responded or not if (i2c->ISR & I2C_ISR_NACKF) { - // If we get a NACK then I2C periph releases the bus, so don't send STOP + // If we get a NACK then I2C periph unconditionally sends a STOP + i2c_wait_isr_set(i2c, I2C_ISR_STOPF); // Don't leak errors from this call i2c->CR1 &= ~I2C_CR1_PE; return -MP_ENODEV; } From e1bc85416a1f15edc95706ebc60255dfb7a9784a Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 9 May 2018 15:59:48 +1000 Subject: [PATCH 618/828] stm32/usb: Fix broken pyb.have_cdc() so it works again. --- ports/stm32/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index b0bdb3a087..718fa898c2 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -389,7 +389,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_usb_vcp_isconnected_obj, pyb_usb_vcp_isconn // deprecated in favour of USB_VCP.isconnected STATIC mp_obj_t pyb_have_cdc(void) { - return pyb_usb_vcp_isconnected(MP_OBJ_NULL); + return pyb_usb_vcp_isconnected(MP_OBJ_FROM_PTR(&pyb_usb_vcp_obj)); } MP_DEFINE_CONST_FUN_OBJ_0(pyb_have_cdc_obj, pyb_have_cdc); From c1115d931fdf3780df92233c3b7bbf2e5cbe82ca Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 9 May 2018 16:00:19 +1000 Subject: [PATCH 619/828] stm32/usb: Use correct type for USB HID object. --- ports/stm32/usb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 718fa898c2..3448c65ddc 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -588,7 +588,7 @@ STATIC mp_obj_t pyb_usb_hid_recv(size_t n_args, const mp_obj_t *args, mp_map_t * }; // parse args - pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(args[0]); + pyb_usb_hid_obj_t *self = MP_OBJ_TO_PTR(args[0]); mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals); @@ -610,7 +610,7 @@ STATIC mp_obj_t pyb_usb_hid_recv(size_t n_args, const mp_obj_t *args, mp_map_t * STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_hid_recv_obj, 1, pyb_usb_hid_recv); STATIC mp_obj_t pyb_usb_hid_send(mp_obj_t self_in, mp_obj_t report_in) { - pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in); + pyb_usb_hid_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_buffer_info_t bufinfo; byte temp_buf[8]; // get the buffer to send from @@ -652,7 +652,7 @@ STATIC const mp_rom_map_elem_t pyb_usb_hid_locals_dict_table[] = { STATIC MP_DEFINE_CONST_DICT(pyb_usb_hid_locals_dict, pyb_usb_hid_locals_dict_table); STATIC mp_uint_t pyb_usb_hid_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { - pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in); + pyb_usb_hid_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_uint_t ret; if (request == MP_STREAM_POLL) { mp_uint_t flags = arg; From eb88803ac859db07726481501aea5c0e6bbf3705 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 9 May 2018 16:15:02 +1000 Subject: [PATCH 620/828] py/{modbuiltins,repl}: Start qstr probing from after empty qstr. The list of qstrs starts with MP_QSTR_NULL followed by MP_QSTR_, and these should never appear in dir() or REPL tab completion, so skip them. --- py/modbuiltins.c | 2 +- py/repl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/py/modbuiltins.c b/py/modbuiltins.c index 5d4ec8ffe4..e45c714e9b 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -186,7 +186,7 @@ STATIC mp_obj_t mp_builtin_dir(size_t n_args, const mp_obj_t *args) { // Make a list of names in the given object // Implemented by probing all possible qstrs with mp_load_method_maybe size_t nqstr = QSTR_TOTAL(); - for (size_t i = 1; i < nqstr; ++i) { + for (size_t i = MP_QSTR_ + 1; i < nqstr; ++i) { mp_obj_t dest[2]; mp_load_method_maybe(args[0], i, dest); if (dest[0] != MP_OBJ_NULL) { diff --git a/py/repl.c b/py/repl.c index 61ae2c1fef..56b1db0115 100644 --- a/py/repl.c +++ b/py/repl.c @@ -176,7 +176,7 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print const char *match_str = NULL; size_t match_len = 0; qstr q_first = 0, q_last; - for (qstr q = 1; q < nqstr; ++q) { + for (qstr q = MP_QSTR_ + 1; q < nqstr; ++q) { size_t d_len; const char *d_str = (const char*)qstr_data(q, &d_len); if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { From bc87b862fd22afb38ed7392b69474286fa5fe19f Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 10 May 2018 23:00:04 +1000 Subject: [PATCH 621/828] py/runtime: Add mp_load_method_protected helper which catches exceptions This new helper function acts like mp_load_method_maybe but is wrapped in an NLR handler so it can catch exceptions. It prevents AttributeError from propagating out, and optionally all other exceptions. This helper can be used to fully implement hasattr (see follow-up commit), and also for cases where mp_load_method_maybe is used but it must now raise an exception. --- py/runtime.c | 16 ++++++++++++++++ py/runtime.h | 1 + 2 files changed, 17 insertions(+) diff --git a/py/runtime.c b/py/runtime.c index 4efb29bec7..8f10630768 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1086,6 +1086,22 @@ void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) { } } +// Acts like mp_load_method_maybe but catches AttributeError, and all other exceptions if requested +void mp_load_method_protected(mp_obj_t obj, qstr attr, mp_obj_t *dest, bool catch_all_exc) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_load_method_maybe(obj, attr, dest); + nlr_pop(); + } else { + if (!catch_all_exc + && !mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type), + MP_OBJ_FROM_PTR(&mp_type_AttributeError))) { + // Re-raise the exception + nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val)); + } + } +} + void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) { DEBUG_OP_printf("store attr %p.%s <- %p\n", base, qstr_str(attr), value); mp_obj_type_t *type = mp_obj_get_type(base); diff --git a/py/runtime.h b/py/runtime.h index 6288e88367..ad65f3f46d 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -132,6 +132,7 @@ mp_obj_t mp_load_attr(mp_obj_t base, qstr attr); void mp_convert_member_lookup(mp_obj_t obj, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest); void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest); void mp_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest); +void mp_load_method_protected(mp_obj_t obj, qstr attr, mp_obj_t *dest, bool catch_all_exc); void mp_load_super_method(qstr attr, mp_obj_t *dest); void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t val); From 529860643bc321267376272356886ef39c4c6bd1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 10 May 2018 23:03:30 +1000 Subject: [PATCH 622/828] py/modbuiltins: Make built-in hasattr work properly for user types. It now allows __getattr__ in a user type to raise AttributeError when the attribute does not exist. --- py/modbuiltins.c | 8 +------- tests/basics/builtin_hasattr.py | 11 +++++++++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/py/modbuiltins.c b/py/modbuiltins.c index e45c714e9b..2f35264159 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -525,14 +525,8 @@ MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_delattr_obj, mp_builtin_delattr); STATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) { qstr attr = mp_obj_str_get_qstr(attr_in); - mp_obj_t dest[2]; - // TODO: https://docs.python.org/3/library/functions.html?highlight=hasattr#hasattr - // explicitly says "This is implemented by calling getattr(object, name) and seeing - // whether it raises an AttributeError or not.", so we should explicitly wrap this - // in nlr_push and handle exception. - mp_load_method_maybe(object_in, attr, dest); - + mp_load_method_protected(object_in, attr, dest, false); return mp_obj_new_bool(dest[0] != MP_OBJ_NULL); } MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj, mp_builtin_hasattr); diff --git a/tests/basics/builtin_hasattr.py b/tests/basics/builtin_hasattr.py index 118a19e579..c60033b963 100644 --- a/tests/basics/builtin_hasattr.py +++ b/tests/basics/builtin_hasattr.py @@ -21,12 +21,19 @@ class C: def __getattr__(self, attr): if attr == "exists": return attr + elif attr == "raise": + raise Exception(123) raise AttributeError c = C() print(hasattr(c, "exists")) -# TODO -#print(hasattr(c, "doesnt_exist")) +print(hasattr(c, "doesnt_exist")) + +# ensure that non-AttributeError exceptions propagate out of hasattr +try: + hasattr(c, "raise") +except Exception as er: + print(er) try: hasattr(1, b'123') From 7241d90272f4dfe4100723393cc2f348f5d32c0a Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 10 May 2018 23:05:43 +1000 Subject: [PATCH 623/828] py/repl: Use mp_load_method_protected to prevent leaking of exceptions. This patch fixes the possibility of a crash of the REPL when tab-completing an object which raises an exception when its attributes are accessed. See issue #3729. --- py/repl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/py/repl.c b/py/repl.c index 56b1db0115..a5a3ee0075 100644 --- a/py/repl.c +++ b/py/repl.c @@ -158,7 +158,7 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print // lookup will fail return 0; } - mp_load_method_maybe(obj, q, dest); + mp_load_method_protected(obj, q, dest, true); obj = dest[0]; // attribute, method, or MP_OBJ_NULL if nothing found if (obj == MP_OBJ_NULL) { @@ -180,7 +180,7 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print size_t d_len; const char *d_str = (const char*)qstr_data(q, &d_len); if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { - mp_load_method_maybe(obj, q, dest); + mp_load_method_protected(obj, q, dest, true); if (dest[0] != MP_OBJ_NULL) { if (match_str == NULL) { match_str = d_str; @@ -234,7 +234,7 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print size_t d_len; const char *d_str = (const char*)qstr_data(q, &d_len); if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { - mp_load_method_maybe(obj, q, dest); + mp_load_method_protected(obj, q, dest, true); if (dest[0] != MP_OBJ_NULL) { int gap = (line_len + WORD_SLOT_LEN - 1) / WORD_SLOT_LEN * WORD_SLOT_LEN - line_len; if (gap < 2) { From 29d28c2574d6c0b93fd3fc869b389a61dee12102 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 10 May 2018 23:07:19 +1000 Subject: [PATCH 624/828] py/modbuiltins: In built-in dir make use of mp_load_method_protected. This gives dir() better behaviour when listing the attributes of a user type that defines __getattr__: it will now not list those attributes for which __getattr__ raises AttributeError (meaning the attribute is not supported by the object). --- py/modbuiltins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/modbuiltins.c b/py/modbuiltins.c index 2f35264159..bc99f82610 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -188,7 +188,7 @@ STATIC mp_obj_t mp_builtin_dir(size_t n_args, const mp_obj_t *args) { size_t nqstr = QSTR_TOTAL(); for (size_t i = MP_QSTR_ + 1; i < nqstr; ++i) { mp_obj_t dest[2]; - mp_load_method_maybe(args[0], i, dest); + mp_load_method_protected(args[0], i, dest, false); if (dest[0] != MP_OBJ_NULL) { mp_obj_list_append(dir, MP_OBJ_NEW_QSTR(i)); } From 3678a6bdc6a925f2bce6423c41f911229836f946 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 10 May 2018 23:10:46 +1000 Subject: [PATCH 625/828] py/modbuiltins: Make built-in dir support the __dir__ special method. If MICROPY_PY_ALL_SPECIAL_METHODS is enabled then dir() will now delegate to the special method __dir__ if the object it is listing has this method. --- py/makeqstrdata.py | 3 +++ py/modbuiltins.c | 7 +++++++ tests/basics/special_methods2.py | 9 +++++++++ 3 files changed, 19 insertions(+) diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py index 38fde1a9c6..3c0a609092 100644 --- a/py/makeqstrdata.py +++ b/py/makeqstrdata.py @@ -114,6 +114,9 @@ def parse_input_headers(infiles): if ident == "": # Sort empty qstr above all still order = -200000 + elif ident == "__dir__": + # Put __dir__ after empty qstr for builtin dir() to work + order = -190000 elif ident.startswith("__"): order -= 100000 qstrs[ident] = (order, ident, qstr) diff --git a/py/modbuiltins.c b/py/modbuiltins.c index bc99f82610..0d511338b0 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -190,6 +190,13 @@ STATIC mp_obj_t mp_builtin_dir(size_t n_args, const mp_obj_t *args) { mp_obj_t dest[2]; mp_load_method_protected(args[0], i, dest, false); if (dest[0] != MP_OBJ_NULL) { + #if MICROPY_PY_ALL_SPECIAL_METHODS + // Support for __dir__: see if we can dispatch to this special method + // This relies on MP_QSTR__dir__ being first after MP_QSTR_ + if (i == MP_QSTR___dir__ && dest[1] != MP_OBJ_NULL) { + return mp_call_method_n_kw(0, 0, dest); + } + #endif mp_obj_list_append(dir, MP_OBJ_NEW_QSTR(i)); } } diff --git a/tests/basics/special_methods2.py b/tests/basics/special_methods2.py index ba7cf27cda..1a38a250c0 100644 --- a/tests/basics/special_methods2.py +++ b/tests/basics/special_methods2.py @@ -94,6 +94,9 @@ class Cud(): print("__isub__ called") return self + def __dir__(self): + return ['a', 'b', 'c'] + cud1 = Cud() cud2 = Cud() @@ -113,6 +116,12 @@ cud2 // cud1 cud1 += cud2 cud1 -= cud2 +# test that dir() delegates to __dir__ special method +print(dir(cud1)) + +# test that dir() does not delegate to __dir__ for the type +print('a' in dir(Cud)) + # TODO: the following operations are not supported on every ports # # ne is not supported, !(eq) is called instead From b208aa189e948481fb341ddb525c2ec432972462 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 11 May 2018 10:36:46 +1000 Subject: [PATCH 626/828] stm32/README: Update to reflect current MCU support. --- ports/stm32/README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ports/stm32/README.md b/ports/stm32/README.md index bb184e8db6..cf539691c8 100644 --- a/ports/stm32/README.md +++ b/ports/stm32/README.md @@ -1,9 +1,9 @@ MicroPython port to STM32 MCUs ============================== -This directory contains the port of MicroPython to ST's line of STM32Fxxx -microcontrollers. It is based on the STM32Cube HAL library and currently -supports: STM32F401, STM32F405, STM32F411, STM32F429, STM32F746. +This directory contains the port of MicroPython to ST's line of STM32 +microcontrollers. Supported MCU series are: STM32F4, STM32F7 and STM32L4. +Parts of the code here utilise the STM32Cube HAL library. The officially supported boards are the line of pyboards: PYBv1.0 and PYBv1.1 (both with STM32F405), and PYBLITEv1.0 (with STM32F411). See @@ -14,6 +14,12 @@ Other boards that are supported include ST Discovery and Nucleo boards. See the boards/ subdirectory, which contains the configuration files used to build each individual board. +The STM32H7 series has preliminary support: there is a working REPL via +USB and UART, as well as very basic peripheral support, but some things do +not work and none of the advanced features of the STM32H7 are yet supported, +such as the clock tree. At this point the STM32H7 should be considered as a +fast version of the STM32F7. + Build instructions ------------------ From 095d3970173f3d4ad6c43bd0c363b727d3a67241 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 11 May 2018 13:44:50 +1000 Subject: [PATCH 627/828] py/objdeque: Fix sign extension bug when computing len of deque object. For cases where size_t is smaller than mp_int_t (eg nan-boxing builds) the difference between two size_t's is not sign extended into mp_int_t and so the result is never negative. This patch fixes this bug by using ssize_t for the type of the result. --- py/objdeque.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/py/objdeque.c b/py/objdeque.c index bbb078103b..1cff1f8d3b 100644 --- a/py/objdeque.c +++ b/py/objdeque.c @@ -24,6 +24,7 @@ * THE SOFTWARE. */ +#include // for ssize_t #include #include "py/mpconfig.h" @@ -75,7 +76,7 @@ STATIC mp_obj_t deque_unary_op(mp_unary_op_t op, mp_obj_t self_in) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->i_get != self->i_put); case MP_UNARY_OP_LEN: { - mp_int_t len = self->i_put - self->i_get; + ssize_t len = self->i_put - self->i_get; if (len < 0) { len += self->alloc; } From 6046e68fe19ca3e88e6e55438be9b2dee98723af Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 11 May 2018 13:48:47 +1000 Subject: [PATCH 628/828] py/repl: Initialise q_last variable to prevent compiler warnings. Some older compilers cannot deduce that q_last is always written to before being read. --- py/repl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/repl.c b/py/repl.c index a5a3ee0075..5dce8bbb7d 100644 --- a/py/repl.c +++ b/py/repl.c @@ -175,7 +175,7 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print // look for matches const char *match_str = NULL; size_t match_len = 0; - qstr q_first = 0, q_last; + qstr q_first = 0, q_last = 0; for (qstr q = MP_QSTR_ + 1; q < nqstr; ++q) { size_t d_len; const char *d_str = (const char*)qstr_data(q, &d_len); From d2c1db1e5cca03c9a34614af6d12045aefe3d719 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 11 May 2018 13:51:18 +1000 Subject: [PATCH 629/828] tests/float/float_parse: Allow test to run on 32-bit archs. Printing of uPy floats can differ by the floating-point precision on different architectures (eg 64-bit vs 32-bit x86), so it's not possible to using printing of floats in some parts of this test. Instead we can just check for equivalence with what is known to be the correct answer. --- tests/float/float_parse.py | 4 ++-- tests/run-tests | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/float/float_parse.py b/tests/float/float_parse.py index 5eb16e79cf..ae6b114f03 100644 --- a/tests/float/float_parse.py +++ b/tests/float/float_parse.py @@ -17,8 +17,8 @@ print(float('.' + '9' * 70 + 'e-50') == float('1e-50')) # tiny fraction with large exponent print(float('.' + '0' * 60 + '1e10') == float('1e-51')) -print(float('.' + '0' * 60 + '9e25')) -print(float('.' + '0' * 60 + '9e40')) +print(float('.' + '0' * 60 + '9e25') == float('9e-36')) +print(float('.' + '0' * 60 + '9e40') == float('9e-21')) # ensure that accuracy is retained when value is close to a subnormal print(float('1.00000000000000000000e-37')) diff --git a/tests/run-tests b/tests/run-tests index 82f05bfa84..afefa264fd 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -324,7 +324,6 @@ def run_tests(pyb, tests, args, base_path="."): skip_tests.add('basics/subclass_native_init.py')# native subclassing corner cases not support skip_tests.add('misc/rge_sm.py') # too large skip_tests.add('micropython/opt_level.py') # don't assume line numbers are stored - skip_tests.add('float/float_parse.py') # minor parsing artifacts with 32-bit floats # Some tests are known to fail on 64-bit machines if pyb is None and platform.architecture()[0] == '64bit': From 421b84af9968e582f324899934f52b3df60381ee Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 11 May 2018 16:39:59 +1000 Subject: [PATCH 630/828] docs: Bump version to 1.9.4. --- docs/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index f9c3ecdb7a..bb8faea88e 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -90,7 +90,7 @@ source_suffix = '.rst' # General information about the project. project = 'MicroPython' -copyright = '2014-2017, Damien P. George, Paul Sokolovsky, and contributors' +copyright = '2014-2018, Damien P. George, Paul Sokolovsky, and contributors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -98,7 +98,7 @@ copyright = '2014-2017, Damien P. George, Paul Sokolovsky, and contributors' # # We don't follow "The short X.Y version" vs "The full version, including alpha/beta/rc tags" # breakdown, so use the same version identifier for both to avoid confusion. -version = release = '1.9.3' +version = release = '1.9.4' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. From 7541be5637c545cbfd8811a6b51e253f9257b833 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 11 May 2018 17:37:16 +1000 Subject: [PATCH 631/828] tests/basics/special_methods2: Enable some additional tests that work. These special methods are all available if MICROPY_PY_ALL_SPECIAL_METHODS is enabled. --- tests/basics/special_methods2.py | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/tests/basics/special_methods2.py b/tests/basics/special_methods2.py index 1a38a250c0..c21618e93d 100644 --- a/tests/basics/special_methods2.py +++ b/tests/basics/special_methods2.py @@ -115,6 +115,13 @@ cud1 / cud2 cud2 // cud1 cud1 += cud2 cud1 -= cud2 +cud1 % 2 +cud1 ** 2 +cud1 | cud2 +cud1 & cud2 +cud1 ^ cud2 +cud1 << 1 +cud1 >> 1 # test that dir() delegates to __dir__ special method print(dir(cud1)) @@ -127,27 +134,6 @@ print('a' in dir(Cud)) # ne is not supported, !(eq) is called instead #cud1 != cud2 # -# binary and is not supported -# cud1 & cud2 -# -# binary lshift is not supported -# cud1<<1 -# -# modulus is not supported -# cud1 % 2 -# -# binary or is not supported -# cud1 | cud2 -# -# pow is not supported -# cud1**2 -# -# rshift is not suported -# cud1>>1 -# -# xor is not supported -# cud1^cud2 -# # in the followin test, cpython still calls __eq__ # cud3=cud1 # cud3==cud1 From 9630376dbca0202321f2aae6ef88ef75cdb5374e Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 7 May 2018 13:36:52 +1000 Subject: [PATCH 632/828] py/mpconfig.h: Be stricter when autodetecting machine endianness. This patch changes 2 things in the endianness detection: 1. Don't assume that __BYTE_ORDER__ not being __ORDER_LITTLE_ENDIAN__ means that the machine is big endian, so add an explicit check that this macro is indeed __ORDER_BIG_ENDIAN__ (same with __BYTE_ORDER, __LITTLE_ENDIAN and __BIG_ENDIAN). A machine could have PDP endianness. 2. Remove the checks which base their autodetection decision on whether any little or big endian macros are defined (eg __LITTLE_ENDIAN__ or __BIG_ENDIAN__). Just because a system defines these does not mean it has that endianness. See issue #3760. --- py/mpconfig.h | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/py/mpconfig.h b/py/mpconfig.h index 532b54ab0b..c42fe78536 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1256,29 +1256,26 @@ typedef double mp_float_t; #elif defined(MP_ENDIANNESS_BIG) #define MP_ENDIANNESS_LITTLE (!MP_ENDIANNESS_BIG) #else - // Endiannes not defined by port so try to autodetect it. + // Endianness not defined by port so try to autodetect it. #if defined(__BYTE_ORDER__) #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #define MP_ENDIANNESS_LITTLE (1) - #else + #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #define MP_ENDIANNESS_LITTLE (0) #endif - #elif defined(__LITTLE_ENDIAN__) || defined(__LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) - #define MP_ENDIANNESS_LITTLE (1) - #elif defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || defined (_BIG_ENDIAN) - #define MP_ENDIANNESS_LITTLE (0) #else #include #if defined(__BYTE_ORDER) #if __BYTE_ORDER == __LITTLE_ENDIAN #define MP_ENDIANNESS_LITTLE (1) - #else + #elif __BYTE_ORDER == __BIG_ENDIAN #define MP_ENDIANNESS_LITTLE (0) #endif - #else - #error endianness not defined and cannot detect it #endif #endif + #ifndef MP_ENDIANNESS_LITTLE + #error endianness not defined and cannot detect it + #endif #define MP_ENDIANNESS_BIG (!MP_ENDIANNESS_LITTLE) #endif From 9f4eda542ae9e7780ddc49c40628707d31ab1014 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 11 May 2018 22:04:56 +1000 Subject: [PATCH 633/828] stm32/usbd_conf.h: Remove unused macros and clean up header file. --- ports/stm32/usbd_conf.h | 43 ------------------------- ports/stm32/usbdev/core/src/usbd_core.c | 2 -- 2 files changed, 45 deletions(-) diff --git a/ports/stm32/usbd_conf.h b/ports/stm32/usbd_conf.h index bf96b7b494..657bba67ed 100644 --- a/ports/stm32/usbd_conf.h +++ b/ports/stm32/usbd_conf.h @@ -29,63 +29,20 @@ ****************************************************************************** */ -/* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __USBD_CONF_H #define __USBD_CONF_H -/* Includes ------------------------------------------------------------------*/ #include #include #include #include -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -/* Common Config */ #define USBD_MAX_NUM_INTERFACES 1 #define USBD_MAX_NUM_CONFIGURATION 1 #define USBD_MAX_STR_DESC_SIZ 0x100 #define USBD_SELF_POWERED 0 #define USBD_DEBUG_LEVEL 0 -/* Exported macro ------------------------------------------------------------*/ -/* Memory management macros */ -/* -these should not be used because the GC is reset on a soft reset but the usb is not -#include "gc.h" -#define USBD_malloc gc_alloc -#define USBD_free gc_free -#define USBD_memset memset -#define USBD_memcpy memcpy -*/ - -/* DEBUG macros */ -#if (USBD_DEBUG_LEVEL > 0) -#define USBD_UsrLog(...) printf(__VA_ARGS__);\ - printf("\n"); -#else -#define USBD_UsrLog(...) -#endif - -#if (USBD_DEBUG_LEVEL > 1) - -#define USBD_ErrLog(...) printf("ERROR: ") ;\ - printf(__VA_ARGS__);\ - printf("\n"); -#else -#define USBD_ErrLog(...) -#endif - -#if (USBD_DEBUG_LEVEL > 2) -#define USBD_DbgLog(...) printf("DEBUG : ") ;\ - printf(__VA_ARGS__);\ - printf("\n"); -#else -#define USBD_DbgLog(...) -#endif - -/* Exported functions ------------------------------------------------------- */ - #endif /* __USBD_CONF_H */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/usbdev/core/src/usbd_core.c b/ports/stm32/usbdev/core/src/usbd_core.c index 23d2bc09f7..0097036633 100644 --- a/ports/stm32/usbdev/core/src/usbd_core.c +++ b/ports/stm32/usbdev/core/src/usbd_core.c @@ -99,7 +99,6 @@ USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev, USBD_DescriptorsTypeDef * /* Check whether the USB Host handle is valid */ if(pdev == NULL) { - USBD_ErrLog("Invalid Device handle"); return USBD_FAIL; } @@ -166,7 +165,6 @@ USBD_StatusTypeDef USBD_RegisterClass(USBD_HandleTypeDef *pdev, const USBD_Clas } else { - USBD_ErrLog("Invalid Class handle"); status = USBD_FAIL; } From 56a273ebff806cd70d1677cf535b80579fad458a Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 11 May 2018 22:17:24 +1000 Subject: [PATCH 634/828] stm32/usbd_conf: Changes files to unix line endings and apply styling. This patch is only cosmetic and has no functional change. --- ports/stm32/usbd_conf.c | 1338 +++++++++++++++++++-------------------- ports/stm32/usbd_conf.h | 96 +-- 2 files changed, 694 insertions(+), 740 deletions(-) diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index 4902da997d..d4a09459b8 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -1,692 +1,646 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - */ - -/** - ****************************************************************************** - * @file USB_Device/CDC_Standalone/Src/usbd_conf.c - * @author MCD Application Team - * @version V1.0.1 - * @date 26-February-2014 - * @brief This file implements the USB Device library callbacks and MSP - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2014 STMicroelectronics

- * - * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.st.com/software_license_agreement_liberty_v2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ****************************************************************************** - */ - -/* Includes ------------------------------------------------------------------*/ -#include "usbd_core.h" -#include "py/obj.h" -#include "py/mphal.h" -#include "irq.h" -#include "usb.h" - -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private macro -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -#if MICROPY_HW_USB_FS -PCD_HandleTypeDef pcd_fs_handle; -#endif -#if MICROPY_HW_USB_HS -PCD_HandleTypeDef pcd_hs_handle; -#endif -/* Private function prototypes -----------------------------------------------*/ -/* Private functions ---------------------------------------------------------*/ - -/******************************************************************************* - PCD BSP Routines -*******************************************************************************/ -/** - * @brief Initializes the PCD MSP. - * @param hpcd: PCD handle - * @retval None - */ -void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) -{ - if(hpcd->Instance == USB_OTG_FS) - { - #if defined(STM32H7) - const uint32_t otg_alt = GPIO_AF10_OTG1_FS; - #else - const uint32_t otg_alt = GPIO_AF10_OTG_FS; - #endif - - mp_hal_pin_config(pin_A11, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, otg_alt); - mp_hal_pin_config_speed(pin_A11, GPIO_SPEED_FREQ_VERY_HIGH); - mp_hal_pin_config(pin_A12, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, otg_alt); - mp_hal_pin_config_speed(pin_A12, GPIO_SPEED_FREQ_VERY_HIGH); - - /* Configure VBUS Pin */ -#if defined(MICROPY_HW_USB_VBUS_DETECT_PIN) - // USB VBUS detect pin is always A9 - mp_hal_pin_config(MICROPY_HW_USB_VBUS_DETECT_PIN, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0); -#endif - -#if defined(MICROPY_HW_USB_OTG_ID_PIN) - // USB ID pin is always A10 - mp_hal_pin_config(MICROPY_HW_USB_OTG_ID_PIN, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, otg_alt); -#endif - - #if defined(STM32H7) - // Keep USB clock running during sleep or else __WFI() will disable the USB - __HAL_RCC_USB2_OTG_FS_CLK_SLEEP_ENABLE(); - __HAL_RCC_USB2_OTG_FS_ULPI_CLK_SLEEP_DISABLE(); - #endif - - /* Enable USB FS Clocks */ - __USB_OTG_FS_CLK_ENABLE(); - -#if defined(STM32L4) - /* Enable VDDUSB */ - if(__HAL_RCC_PWR_IS_CLK_DISABLED()) - { - __HAL_RCC_PWR_CLK_ENABLE(); - HAL_PWREx_EnableVddUSB(); - __HAL_RCC_PWR_CLK_DISABLE(); - } - else - { - HAL_PWREx_EnableVddUSB(); - } -#endif - - /* Set USBFS Interrupt priority */ - NVIC_SetPriority(OTG_FS_IRQn, IRQ_PRI_OTG_FS); - - /* Enable USBFS Interrupt */ - HAL_NVIC_EnableIRQ(OTG_FS_IRQn); - } -#if MICROPY_HW_USB_HS - else if(hpcd->Instance == USB_OTG_HS) - { -#if MICROPY_HW_USB_HS_IN_FS - - /* Configure USB FS GPIOs */ - mp_hal_pin_config(pin_B14, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, GPIO_AF12_OTG_HS_FS); - mp_hal_pin_config_speed(pin_B14, GPIO_SPEED_FREQ_VERY_HIGH); - mp_hal_pin_config(pin_B15, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, GPIO_AF12_OTG_HS_FS); - mp_hal_pin_config_speed(pin_B15, GPIO_SPEED_FREQ_VERY_HIGH); - -#if defined(MICROPY_HW_USB_VBUS_DETECT_PIN) - /* Configure VBUS Pin */ - mp_hal_pin_config(MICROPY_HW_USB_VBUS_DETECT_PIN, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0); -#endif - -#if defined(MICROPY_HW_USB_OTG_ID_PIN) - /* Configure ID pin */ - mp_hal_pin_config(MICROPY_HW_USB_OTG_ID_PIN, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, GPIO_AF12_OTG_HS_FS); -#endif - /* - * Enable calling WFI and correct - * function of the embedded USB_FS_IN_HS phy - */ - __HAL_RCC_USB_OTG_HS_ULPI_CLK_SLEEP_DISABLE(); - __HAL_RCC_USB_OTG_HS_CLK_SLEEP_ENABLE(); - - /* Enable USB HS Clocks */ - - #if defined(STM32F723xx) || defined(STM32F733xx) - // Needs to remain awake during sleep or else __WFI() will disable the USB - __HAL_RCC_USB_OTG_HS_ULPI_CLK_SLEEP_ENABLE(); - __HAL_RCC_OTGPHYC_CLK_ENABLE(); - __HAL_RCC_USB_OTG_HS_ULPI_CLK_ENABLE(); - #endif - - __HAL_RCC_USB_OTG_HS_CLK_ENABLE(); - -#else // !MICROPY_HW_USB_HS_IN_FS - GPIO_InitTypeDef GPIO_InitStruct; - - /* Configure USB HS GPIOs */ - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); - __HAL_RCC_GPIOC_CLK_ENABLE(); - __HAL_RCC_GPIOH_CLK_ENABLE(); - __HAL_RCC_GPIOI_CLK_ENABLE(); - - /* CLK */ - GPIO_InitStruct.Pin = GPIO_PIN_5; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - - /* D0 */ - GPIO_InitStruct.Pin = GPIO_PIN_3; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - - /* D1 D2 D3 D4 D5 D6 D7 */ - GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_5 |\ - GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - - /* STP */ - GPIO_InitStruct.Pin = GPIO_PIN_0; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); - - /* NXT */ - GPIO_InitStruct.Pin = GPIO_PIN_4; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; - HAL_GPIO_Init(GPIOH, &GPIO_InitStruct); - - /* DIR */ - GPIO_InitStruct.Pin = GPIO_PIN_11; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; - HAL_GPIO_Init(GPIOI, &GPIO_InitStruct); - - /* Enable USB HS Clocks */ - __USB_OTG_HS_CLK_ENABLE(); - __USB_OTG_HS_ULPI_CLK_ENABLE(); -#endif // !MICROPY_HW_USB_HS_IN_FS - - /* Set USBHS Interrupt to the lowest priority */ - NVIC_SetPriority(OTG_HS_IRQn, IRQ_PRI_OTG_HS); - - /* Enable USBHS Interrupt */ - HAL_NVIC_EnableIRQ(OTG_HS_IRQn); - } -#endif // MICROPY_HW_USB_HS -} -/** - * @brief DeInitializes the PCD MSP. - * @param hpcd: PCD handle - * @retval None - */ -void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd) -{ - if(hpcd->Instance == USB_OTG_FS) - { - /* Disable USB FS Clocks */ - __USB_OTG_FS_CLK_DISABLE(); - __SYSCFG_CLK_DISABLE(); - } - #if MICROPY_HW_USB_HS - else if(hpcd->Instance == USB_OTG_HS) - { - /* Disable USB FS Clocks */ - __USB_OTG_HS_CLK_DISABLE(); - __SYSCFG_CLK_DISABLE(); - } - #endif -} - -/******************************************************************************* - LL Driver Callbacks (PCD -> USB Device Library) -*******************************************************************************/ - - -/** - * @brief Setup stage callback. - * @param hpcd: PCD handle - * @retval None - */ -void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) -{ - USBD_LL_SetupStage(hpcd->pData, (uint8_t *)hpcd->Setup); -} - -/** - * @brief Data Out stage callback. - * @param hpcd: PCD handle - * @param epnum: Endpoint Number - * @retval None - */ -void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) -{ - USBD_LL_DataOutStage(hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff); -} - -/** - * @brief Data In stage callback. - * @param hpcd: PCD handle - * @param epnum: Endpoint Number - * @retval None - */ -void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) -{ - USBD_LL_DataInStage(hpcd->pData, epnum, hpcd->IN_ep[epnum].xfer_buff); -} - -/** - * @brief SOF callback. - * @param hpcd: PCD handle - * @retval None - */ -/* -This is now handled by the USB CDC interface. -void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) -{ - USBD_LL_SOF(hpcd->pData); -} -*/ - -/** - * @brief Reset callback. - * @param hpcd: PCD handle - * @retval None - */ -void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd) -{ - USBD_SpeedTypeDef speed = USBD_SPEED_FULL; - - /* Set USB Current Speed */ - switch(hpcd->Init.speed) - { -#if defined(PCD_SPEED_HIGH) - case PCD_SPEED_HIGH: - speed = USBD_SPEED_HIGH; - break; -#endif - - case PCD_SPEED_FULL: - speed = USBD_SPEED_FULL; - break; - - default: - speed = USBD_SPEED_FULL; - break; - } - USBD_LL_SetSpeed(hpcd->pData, speed); - - /* Reset Device */ - USBD_LL_Reset(hpcd->pData); -} - -/** - * @brief Suspend callback. - * @param hpcd: PCD handle - * @retval None - */ -void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd) -{ - USBD_LL_Suspend(hpcd->pData); -} - -/** - * @brief Resume callback. - * @param hpcd: PCD handle - * @retval None - */ -void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd) -{ - USBD_LL_Resume(hpcd->pData); -} - -/** - * @brief ISOC Out Incomplete callback. - * @param hpcd: PCD handle - * @param epnum: Endpoint Number - * @retval None - */ -void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) -{ - USBD_LL_IsoOUTIncomplete(hpcd->pData, epnum); -} - -/** - * @brief ISOC In Incomplete callback. - * @param hpcd: PCD handle - * @param epnum: Endpoint Number - * @retval None - */ -void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) -{ - USBD_LL_IsoINIncomplete(hpcd->pData, epnum); -} - -/** - * @brief Connect callback. - * @param hpcd: PCD handle - * @retval None - */ -void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd) -{ - USBD_LL_DevConnected(hpcd->pData); -} - -/** - * @brief Disconnect callback. - * @param hpcd: PCD handle - * @retval None - */ -void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) -{ - USBD_LL_DevDisconnected(hpcd->pData); -} - -/******************************************************************************* - LL Driver Interface (USB Device Library --> PCD) -*******************************************************************************/ -/** - * @brief Initializes the Low Level portion of the Device driver. - * @param pdev: Device handle - * @retval USBD Status - */ -USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev, int high_speed) -{ -#if MICROPY_HW_USB_FS -if (pdev->id == USB_PHY_FS_ID) -{ - /*Set LL Driver parameters */ - pcd_fs_handle.Instance = USB_OTG_FS; - pcd_fs_handle.Init.dev_endpoints = 4; - pcd_fs_handle.Init.use_dedicated_ep1 = 0; - pcd_fs_handle.Init.ep0_mps = 0x40; - pcd_fs_handle.Init.dma_enable = 0; - pcd_fs_handle.Init.low_power_enable = 0; - pcd_fs_handle.Init.phy_itface = PCD_PHY_EMBEDDED; - pcd_fs_handle.Init.Sof_enable = 1; - pcd_fs_handle.Init.speed = PCD_SPEED_FULL; -#if defined(STM32L4) - pcd_fs_handle.Init.lpm_enable = DISABLE; - pcd_fs_handle.Init.battery_charging_enable = DISABLE; -#endif -#if !defined(MICROPY_HW_USB_VBUS_DETECT_PIN) - pcd_fs_handle.Init.vbus_sensing_enable = 0; // No VBUS Sensing on USB0 -#else - pcd_fs_handle.Init.vbus_sensing_enable = 1; -#endif - /* Link The driver to the stack */ - pcd_fs_handle.pData = pdev; - pdev->pData = &pcd_fs_handle; - /*Initialize LL Driver */ - HAL_PCD_Init(&pcd_fs_handle); - - HAL_PCD_SetRxFiFo(&pcd_fs_handle, 0x80); - HAL_PCD_SetTxFiFo(&pcd_fs_handle, 0, 0x20); - HAL_PCD_SetTxFiFo(&pcd_fs_handle, 1, 0x40); - HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 0x20); - HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 0x40); -} -#endif -#if MICROPY_HW_USB_HS -if (pdev->id == USB_PHY_HS_ID) -{ -#if MICROPY_HW_USB_HS_IN_FS - /*Set LL Driver parameters */ - pcd_hs_handle.Instance = USB_OTG_HS; - pcd_hs_handle.Init.dev_endpoints = 4; - pcd_hs_handle.Init.use_dedicated_ep1 = 0; - pcd_hs_handle.Init.ep0_mps = 0x40; - pcd_hs_handle.Init.dma_enable = 0; - pcd_hs_handle.Init.low_power_enable = 0; - #if defined(STM32F723xx) || defined(STM32F733xx) - pcd_hs_handle.Init.phy_itface = USB_OTG_HS_EMBEDDED_PHY; - #else - pcd_hs_handle.Init.phy_itface = PCD_PHY_EMBEDDED; - #endif - pcd_hs_handle.Init.Sof_enable = 1; - if (high_speed) { - pcd_hs_handle.Init.speed = PCD_SPEED_HIGH; - } else { - pcd_hs_handle.Init.speed = PCD_SPEED_HIGH_IN_FULL; - } -#if !defined(MICROPY_HW_USB_VBUS_DETECT_PIN) - pcd_hs_handle.Init.vbus_sensing_enable = 0; // No VBUS Sensing on USB0 -#else - pcd_hs_handle.Init.vbus_sensing_enable = 1; -#endif - pcd_hs_handle.Init.use_external_vbus = 0; - /* Link The driver to the stack */ - pcd_hs_handle.pData = pdev; - pdev->pData = &pcd_hs_handle; - /*Initialize LL Driver */ - HAL_PCD_Init(&pcd_hs_handle); - - HAL_PCD_SetRxFiFo(&pcd_hs_handle, 0x200); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 0x20); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 0x100); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 2, 0x20); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 0xc0); -#else // !MICROPY_HW_USB_HS_IN_FS - /*Set LL Driver parameters */ - pcd_hs_handle.Instance = USB_OTG_HS; - pcd_hs_handle.Init.dev_endpoints = 6; - pcd_hs_handle.Init.use_dedicated_ep1 = 0; - pcd_hs_handle.Init.ep0_mps = 0x40; - - /* Be aware that enabling USB-DMA mode will result in data being sent only by - multiple of 4 packet sizes. This is due to the fact that USB-DMA does - not allow sending data from non word-aligned addresses. - For this specific application, it is advised to not enable this option - unless required. */ - pcd_hs_handle.Init.dma_enable = 0; - - pcd_hs_handle.Init.low_power_enable = 0; - pcd_hs_handle.Init.phy_itface = PCD_PHY_ULPI; - pcd_hs_handle.Init.Sof_enable = 1; - pcd_hs_handle.Init.speed = PCD_SPEED_HIGH; - pcd_hs_handle.Init.vbus_sensing_enable = 1; - /* Link The driver to the stack */ - pcd_hs_handle.pData = pdev; - pdev->pData = &pcd_hs_handle; - /*Initialize LL Driver */ - HAL_PCD_Init(&pcd_hs_handle); - - HAL_PCD_SetRxFiFo(&pcd_hs_handle, 0x200); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 0x80); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 0x174); - -#endif // !MICROPY_HW_USB_HS_IN_FS -} -#endif // MICROPY_HW_USB_HS - return USBD_OK; -} - -/** - * @brief De-Initializes the Low Level portion of the Device driver. - * @param pdev: Device handle - * @retval USBD Status - */ -USBD_StatusTypeDef USBD_LL_DeInit(USBD_HandleTypeDef *pdev) -{ - HAL_PCD_DeInit(pdev->pData); - return USBD_OK; -} - -/** - * @brief Starts the Low Level portion of the Device driver. - * @param pdev: Device handle - * @retval USBD Status - */ -USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev) -{ - HAL_PCD_Start(pdev->pData); - return USBD_OK; -} - -/** - * @brief Stops the Low Level portion of the Device driver. - * @param pdev: Device handle - * @retval USBD Status - */ -USBD_StatusTypeDef USBD_LL_Stop(USBD_HandleTypeDef *pdev) -{ - HAL_PCD_Stop(pdev->pData); - return USBD_OK; -} - -/** - * @brief Opens an endpoint of the Low Level Driver. - * @param pdev: Device handle - * @param ep_addr: Endpoint Number - * @param ep_type: Endpoint Type - * @param ep_mps: Endpoint Max Packet Size - * @retval USBD Status - */ -USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev, - uint8_t ep_addr, - uint8_t ep_type, - uint16_t ep_mps) -{ - HAL_PCD_EP_Open(pdev->pData, ep_addr, ep_mps, ep_type); - return USBD_OK; -} - -/** - * @brief Closes an endpoint of the Low Level Driver. - * @param pdev: Device handle - * @param ep_addr: Endpoint Number - * @retval USBD Status - */ -USBD_StatusTypeDef USBD_LL_CloseEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) -{ - HAL_PCD_EP_Close(pdev->pData, ep_addr); - return USBD_OK; -} - -/** - * @brief Flushes an endpoint of the Low Level Driver. - * @param pdev: Device handle - * @param ep_addr: Endpoint Number - * @retval USBD Status - */ -USBD_StatusTypeDef USBD_LL_FlushEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) -{ - HAL_PCD_EP_Flush(pdev->pData, ep_addr); - return USBD_OK; -} - -/** - * @brief Sets a Stall condition on an endpoint of the Low Level Driver. - * @param pdev: Device handle - * @param ep_addr: Endpoint Number - * @retval USBD Status - */ -USBD_StatusTypeDef USBD_LL_StallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) -{ - HAL_PCD_EP_SetStall(pdev->pData, ep_addr); - return USBD_OK; -} - -/** - * @brief Clears a Stall condition on an endpoint of the Low Level Driver. - * @param pdev: Device handle - * @param ep_addr: Endpoint Number - * @retval USBD Status - */ -USBD_StatusTypeDef USBD_LL_ClearStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) -{ - HAL_PCD_EP_ClrStall(pdev->pData, ep_addr); - return USBD_OK; -} - -/** - * @brief Returns Stall condition. - * @param pdev: Device handle - * @param ep_addr: Endpoint Number - * @retval Stall (1: yes, 0: No) - */ -uint8_t USBD_LL_IsStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) -{ - PCD_HandleTypeDef *hpcd = pdev->pData; - - if((ep_addr & 0x80) == 0x80) - { - return hpcd->IN_ep[ep_addr & 0x7F].is_stall; - } - else - { - return hpcd->OUT_ep[ep_addr & 0x7F].is_stall; - } -} - -/** - * @brief Assigns an USB address to the device - * @param pdev: Device handle - * @param dev_addr: USB address - * @retval USBD Status - */ -USBD_StatusTypeDef USBD_LL_SetUSBAddress(USBD_HandleTypeDef *pdev, uint8_t dev_addr) -{ - HAL_PCD_SetAddress(pdev->pData, dev_addr); - return USBD_OK; -} - -/** - * @brief Transmits data over an endpoint - * @param pdev: Device handle - * @param ep_addr: Endpoint Number - * @param pbuf: Pointer to data to be sent - * @param size: Data size - * @retval USBD Status - */ -USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *pdev, - uint8_t ep_addr, - uint8_t *pbuf, - uint16_t size) -{ - HAL_PCD_EP_Transmit(pdev->pData, ep_addr, pbuf, size); - return USBD_OK; -} - -/** - * @brief Prepares an endpoint for reception - * @param pdev: Device handle - * @param ep_addr: Endpoint Number - * @param pbuf:pointer to data to be received - * @param size: data size - * @retval USBD Status - */ -USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, - uint8_t ep_addr, - uint8_t *pbuf, - uint16_t size) -{ - HAL_PCD_EP_Receive(pdev->pData, ep_addr, pbuf, size); - return USBD_OK; -} - -/** - * @brief Returns the last transfered packet size. - * @param pdev: Device handle - * @param ep_addr: Endpoint Number - * @retval Recived Data Size - */ -uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr) -{ - return HAL_PCD_EP_GetRxCount(pdev->pData, ep_addr); -} - -/** - * @brief Delay routine for the USB Device Library - * @param Delay: Delay in ms - * @retval None - */ -void USBD_LL_Delay(uint32_t Delay) -{ - HAL_Delay(Delay); -} - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +/* + * This file is part of the MicroPython project, http://micropython.org/ + */ + +/** + ****************************************************************************** + * @file USB_Device/CDC_Standalone/Src/usbd_conf.c + * @author MCD Application Team + * @version V1.0.1 + * @date 26-February-2014 + * @brief This file implements the USB Device library callbacks and MSP + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +#include "usbd_core.h" +#include "py/obj.h" +#include "py/mphal.h" +#include "irq.h" +#include "usb.h" + +#if MICROPY_HW_USB_FS +PCD_HandleTypeDef pcd_fs_handle; +#endif +#if MICROPY_HW_USB_HS +PCD_HandleTypeDef pcd_hs_handle; +#endif + +/******************************************************************************* + PCD BSP Routines +*******************************************************************************/ + +/** + * @brief Initializes the PCD MSP. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { + if (hpcd->Instance == USB_OTG_FS) { + #if defined(STM32H7) + const uint32_t otg_alt = GPIO_AF10_OTG1_FS; + #else + const uint32_t otg_alt = GPIO_AF10_OTG_FS; + #endif + + mp_hal_pin_config(pin_A11, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, otg_alt); + mp_hal_pin_config_speed(pin_A11, GPIO_SPEED_FREQ_VERY_HIGH); + mp_hal_pin_config(pin_A12, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, otg_alt); + mp_hal_pin_config_speed(pin_A12, GPIO_SPEED_FREQ_VERY_HIGH); + + #if defined(MICROPY_HW_USB_VBUS_DETECT_PIN) + // USB VBUS detect pin is always A9 + mp_hal_pin_config(MICROPY_HW_USB_VBUS_DETECT_PIN, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0); + #endif + + #if defined(MICROPY_HW_USB_OTG_ID_PIN) + // USB ID pin is always A10 + mp_hal_pin_config(MICROPY_HW_USB_OTG_ID_PIN, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, otg_alt); + #endif + + #if defined(STM32H7) + // Keep USB clock running during sleep or else __WFI() will disable the USB + __HAL_RCC_USB2_OTG_FS_CLK_SLEEP_ENABLE(); + __HAL_RCC_USB2_OTG_FS_ULPI_CLK_SLEEP_DISABLE(); + #endif + + // Enable USB FS Clocks + __USB_OTG_FS_CLK_ENABLE(); + + #if defined(STM32L4) + // Enable VDDUSB + if (__HAL_RCC_PWR_IS_CLK_DISABLED()) { + __HAL_RCC_PWR_CLK_ENABLE(); + HAL_PWREx_EnableVddUSB(); + __HAL_RCC_PWR_CLK_DISABLE(); + } else { + HAL_PWREx_EnableVddUSB(); + } + #endif + + // Configure and enable USB FS interrupt + NVIC_SetPriority(OTG_FS_IRQn, IRQ_PRI_OTG_FS); + HAL_NVIC_EnableIRQ(OTG_FS_IRQn); + } + #if MICROPY_HW_USB_HS + else if (hpcd->Instance == USB_OTG_HS) { + #if MICROPY_HW_USB_HS_IN_FS + + // Configure USB FS GPIOs + mp_hal_pin_config(pin_B14, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, GPIO_AF12_OTG_HS_FS); + mp_hal_pin_config_speed(pin_B14, GPIO_SPEED_FREQ_VERY_HIGH); + mp_hal_pin_config(pin_B15, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, GPIO_AF12_OTG_HS_FS); + mp_hal_pin_config_speed(pin_B15, GPIO_SPEED_FREQ_VERY_HIGH); + + #if defined(MICROPY_HW_USB_VBUS_DETECT_PIN) + // Configure VBUS Pin + mp_hal_pin_config(MICROPY_HW_USB_VBUS_DETECT_PIN, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0); + #endif + + #if defined(MICROPY_HW_USB_OTG_ID_PIN) + // Configure ID pin + mp_hal_pin_config(MICROPY_HW_USB_OTG_ID_PIN, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, GPIO_AF12_OTG_HS_FS); + #endif + + // Enable calling WFI and correct function of the embedded USB_FS_IN_HS phy + __HAL_RCC_USB_OTG_HS_ULPI_CLK_SLEEP_DISABLE(); + __HAL_RCC_USB_OTG_HS_CLK_SLEEP_ENABLE(); + + // Enable USB HS Clocks + + #if defined(STM32F723xx) || defined(STM32F733xx) + // Needs to remain awake during sleep or else __WFI() will disable the USB + __HAL_RCC_USB_OTG_HS_ULPI_CLK_SLEEP_ENABLE(); + __HAL_RCC_OTGPHYC_CLK_ENABLE(); + __HAL_RCC_USB_OTG_HS_ULPI_CLK_ENABLE(); + #endif + + __HAL_RCC_USB_OTG_HS_CLK_ENABLE(); + + #else // !MICROPY_HW_USB_HS_IN_FS + + GPIO_InitTypeDef GPIO_InitStruct; + + // Configure USB HS GPIOs + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); + __HAL_RCC_GPIOI_CLK_ENABLE(); + + // CLK + GPIO_InitStruct.Pin = GPIO_PIN_5; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + // D0 + GPIO_InitStruct.Pin = GPIO_PIN_3; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + // D1 D2 D3 D4 D5 D6 D7 + GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_5 |\ + GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + // STP + GPIO_InitStruct.Pin = GPIO_PIN_0; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + // NXT + GPIO_InitStruct.Pin = GPIO_PIN_4; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; + HAL_GPIO_Init(GPIOH, &GPIO_InitStruct); + + // DIR + GPIO_InitStruct.Pin = GPIO_PIN_11; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; + HAL_GPIO_Init(GPIOI, &GPIO_InitStruct); + + // Enable USB HS Clocks + __USB_OTG_HS_CLK_ENABLE(); + __USB_OTG_HS_ULPI_CLK_ENABLE(); + + #endif // !MICROPY_HW_USB_HS_IN_FS + + // Configure and enable USB HS interrupt + NVIC_SetPriority(OTG_HS_IRQn, IRQ_PRI_OTG_HS); + HAL_NVIC_EnableIRQ(OTG_HS_IRQn); + } + #endif // MICROPY_HW_USB_HS +} + +/** + * @brief DeInitializes the PCD MSP. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd) { + if (hpcd->Instance == USB_OTG_FS) { + /* Disable USB FS Clocks */ + __USB_OTG_FS_CLK_DISABLE(); + __SYSCFG_CLK_DISABLE(); + } + #if MICROPY_HW_USB_HS + else if (hpcd->Instance == USB_OTG_HS) { + /* Disable USB FS Clocks */ + __USB_OTG_HS_CLK_DISABLE(); + __SYSCFG_CLK_DISABLE(); + } + #endif +} + +/******************************************************************************* + LL Driver Callbacks (PCD -> USB Device Library) +*******************************************************************************/ + +/** + * @brief Setup stage callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) { + USBD_LL_SetupStage(hpcd->pData, (uint8_t *)hpcd->Setup); +} + +/** + * @brief Data Out stage callback. + * @param hpcd: PCD handle + * @param epnum: Endpoint Number + * @retval None + */ +void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) { + USBD_LL_DataOutStage(hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff); +} + +/** + * @brief Data In stage callback. + * @param hpcd: PCD handle + * @param epnum: Endpoint Number + * @retval None + */ +void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) { + USBD_LL_DataInStage(hpcd->pData, epnum, hpcd->IN_ep[epnum].xfer_buff); +} + +/** + * @brief SOF callback. + * @param hpcd: PCD handle + * @retval None + */ +/* +This is now handled by the USB CDC interface. +void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) +{ + USBD_LL_SOF(hpcd->pData); +} +*/ + +/** + * @brief Reset callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd) { + USBD_SpeedTypeDef speed = USBD_SPEED_FULL; + + // Set USB Current Speed + switch (hpcd->Init.speed) { + #if defined(PCD_SPEED_HIGH) + case PCD_SPEED_HIGH: + speed = USBD_SPEED_HIGH; + break; + #endif + + case PCD_SPEED_FULL: + speed = USBD_SPEED_FULL; + break; + + default: + speed = USBD_SPEED_FULL; + break; + } + USBD_LL_SetSpeed(hpcd->pData, speed); + + // Reset Device + USBD_LL_Reset(hpcd->pData); +} + +/** + * @brief Suspend callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd) { + USBD_LL_Suspend(hpcd->pData); +} + +/** + * @brief Resume callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd) { + USBD_LL_Resume(hpcd->pData); +} + +/** + * @brief ISOC Out Incomplete callback. + * @param hpcd: PCD handle + * @param epnum: Endpoint Number + * @retval None + */ +void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) { + USBD_LL_IsoOUTIncomplete(hpcd->pData, epnum); +} + +/** + * @brief ISOC In Incomplete callback. + * @param hpcd: PCD handle + * @param epnum: Endpoint Number + * @retval None + */ +void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) { + USBD_LL_IsoINIncomplete(hpcd->pData, epnum); +} + +/** + * @brief Connect callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd) { + USBD_LL_DevConnected(hpcd->pData); +} + +/** + * @brief Disconnect callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) { + USBD_LL_DevDisconnected(hpcd->pData); +} + +/******************************************************************************* + LL Driver Interface (USB Device Library --> PCD) +*******************************************************************************/ + +/** + * @brief Initializes the Low Level portion of the Device driver. + * @param pdev: Device handle + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { + #if MICROPY_HW_USB_FS + if (pdev->id == USB_PHY_FS_ID) { + // Set LL Driver parameters + pcd_fs_handle.Instance = USB_OTG_FS; + pcd_fs_handle.Init.dev_endpoints = 4; + pcd_fs_handle.Init.use_dedicated_ep1 = 0; + pcd_fs_handle.Init.ep0_mps = 0x40; + pcd_fs_handle.Init.dma_enable = 0; + pcd_fs_handle.Init.low_power_enable = 0; + pcd_fs_handle.Init.phy_itface = PCD_PHY_EMBEDDED; + pcd_fs_handle.Init.Sof_enable = 1; + pcd_fs_handle.Init.speed = PCD_SPEED_FULL; + #if defined(STM32L4) + pcd_fs_handle.Init.lpm_enable = DISABLE; + pcd_fs_handle.Init.battery_charging_enable = DISABLE; + #endif + #if !defined(MICROPY_HW_USB_VBUS_DETECT_PIN) + pcd_fs_handle.Init.vbus_sensing_enable = 0; // No VBUS Sensing on USB0 + #else + pcd_fs_handle.Init.vbus_sensing_enable = 1; + #endif + + // Link The driver to the stack + pcd_fs_handle.pData = pdev; + pdev->pData = &pcd_fs_handle; + + // Initialize LL Driver + HAL_PCD_Init(&pcd_fs_handle); + + HAL_PCD_SetRxFiFo(&pcd_fs_handle, 0x80); + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 0, 0x20); + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 1, 0x40); + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 0x20); + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 0x40); + } + #endif + #if MICROPY_HW_USB_HS + if (pdev->id == USB_PHY_HS_ID) { + #if MICROPY_HW_USB_HS_IN_FS + + // Set LL Driver parameters + pcd_hs_handle.Instance = USB_OTG_HS; + pcd_hs_handle.Init.dev_endpoints = 4; + pcd_hs_handle.Init.use_dedicated_ep1 = 0; + pcd_hs_handle.Init.ep0_mps = 0x40; + pcd_hs_handle.Init.dma_enable = 0; + pcd_hs_handle.Init.low_power_enable = 0; + #if defined(STM32F723xx) || defined(STM32F733xx) + pcd_hs_handle.Init.phy_itface = USB_OTG_HS_EMBEDDED_PHY; + #else + pcd_hs_handle.Init.phy_itface = PCD_PHY_EMBEDDED; + #endif + pcd_hs_handle.Init.Sof_enable = 1; + if (high_speed) { + pcd_hs_handle.Init.speed = PCD_SPEED_HIGH; + } else { + pcd_hs_handle.Init.speed = PCD_SPEED_HIGH_IN_FULL; + } + #if !defined(MICROPY_HW_USB_VBUS_DETECT_PIN) + pcd_hs_handle.Init.vbus_sensing_enable = 0; // No VBUS Sensing on USB0 + #else + pcd_hs_handle.Init.vbus_sensing_enable = 1; + #endif + pcd_hs_handle.Init.use_external_vbus = 0; + + // Link The driver to the stack + pcd_hs_handle.pData = pdev; + pdev->pData = &pcd_hs_handle; + + // Initialize LL Driver + HAL_PCD_Init(&pcd_hs_handle); + + HAL_PCD_SetRxFiFo(&pcd_hs_handle, 0x200); + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 0x20); + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 0x100); + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 2, 0x20); + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 0xc0); + + #else // !MICROPY_HW_USB_HS_IN_FS + + // Set LL Driver parameters + pcd_hs_handle.Instance = USB_OTG_HS; + pcd_hs_handle.Init.dev_endpoints = 6; + pcd_hs_handle.Init.use_dedicated_ep1 = 0; + pcd_hs_handle.Init.ep0_mps = 0x40; + + /* Be aware that enabling USB-DMA mode will result in data being sent only by + multiple of 4 packet sizes. This is due to the fact that USB-DMA does + not allow sending data from non word-aligned addresses. + For this specific application, it is advised to not enable this option + unless required. */ + pcd_hs_handle.Init.dma_enable = 0; + + pcd_hs_handle.Init.low_power_enable = 0; + pcd_hs_handle.Init.phy_itface = PCD_PHY_ULPI; + pcd_hs_handle.Init.Sof_enable = 1; + pcd_hs_handle.Init.speed = PCD_SPEED_HIGH; + pcd_hs_handle.Init.vbus_sensing_enable = 1; + + // Link The driver to the stack + pcd_hs_handle.pData = pdev; + pdev->pData = &pcd_hs_handle; + + // Initialize LL Driver + HAL_PCD_Init(&pcd_hs_handle); + + HAL_PCD_SetRxFiFo(&pcd_hs_handle, 0x200); + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 0x80); + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 0x174); + + #endif // !MICROPY_HW_USB_HS_IN_FS + } + #endif // MICROPY_HW_USB_HS + + return USBD_OK; +} + +/** + * @brief De-Initializes the Low Level portion of the Device driver. + * @param pdev: Device handle + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_DeInit(USBD_HandleTypeDef *pdev) { + HAL_PCD_DeInit(pdev->pData); + return USBD_OK; +} + +/** + * @brief Starts the Low Level portion of the Device driver. + * @param pdev: Device handle + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev) { + HAL_PCD_Start(pdev->pData); + return USBD_OK; +} + +/** + * @brief Stops the Low Level portion of the Device driver. + * @param pdev: Device handle + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_Stop(USBD_HandleTypeDef *pdev) { + HAL_PCD_Stop(pdev->pData); + return USBD_OK; +} + +/** + * @brief Opens an endpoint of the Low Level Driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint Number + * @param ep_type: Endpoint Type + * @param ep_mps: Endpoint Max Packet Size + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev, + uint8_t ep_addr, uint8_t ep_type, uint16_t ep_mps) { + HAL_PCD_EP_Open(pdev->pData, ep_addr, ep_mps, ep_type); + return USBD_OK; +} + +/** + * @brief Closes an endpoint of the Low Level Driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint Number + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_CloseEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { + HAL_PCD_EP_Close(pdev->pData, ep_addr); + return USBD_OK; +} + +/** + * @brief Flushes an endpoint of the Low Level Driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint Number + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_FlushEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { + HAL_PCD_EP_Flush(pdev->pData, ep_addr); + return USBD_OK; +} + +/** + * @brief Sets a Stall condition on an endpoint of the Low Level Driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint Number + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_StallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { + HAL_PCD_EP_SetStall(pdev->pData, ep_addr); + return USBD_OK; +} + +/** + * @brief Clears a Stall condition on an endpoint of the Low Level Driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint Number + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_ClearStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { + HAL_PCD_EP_ClrStall(pdev->pData, ep_addr); + return USBD_OK; +} + +/** + * @brief Returns Stall condition. + * @param pdev: Device handle + * @param ep_addr: Endpoint Number + * @retval Stall (1: yes, 0: No) + */ +uint8_t USBD_LL_IsStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { + PCD_HandleTypeDef *hpcd = pdev->pData; + + if ((ep_addr & 0x80) == 0x80) { + return hpcd->IN_ep[ep_addr & 0x7F].is_stall; + } else { + return hpcd->OUT_ep[ep_addr & 0x7F].is_stall; + } +} + +/** + * @brief Assigns an USB address to the device + * @param pdev: Device handle + * @param dev_addr: USB address + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_SetUSBAddress(USBD_HandleTypeDef *pdev, uint8_t dev_addr) { + HAL_PCD_SetAddress(pdev->pData, dev_addr); + return USBD_OK; +} + +/** + * @brief Transmits data over an endpoint + * @param pdev: Device handle + * @param ep_addr: Endpoint Number + * @param pbuf: Pointer to data to be sent + * @param size: Data size + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *pdev, + uint8_t ep_addr, uint8_t *pbuf, uint16_t size) { + HAL_PCD_EP_Transmit(pdev->pData, ep_addr, pbuf, size); + return USBD_OK; +} + +/** + * @brief Prepares an endpoint for reception + * @param pdev: Device handle + * @param ep_addr: Endpoint Number + * @param pbuf:pointer to data to be received + * @param size: data size + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, + uint8_t ep_addr, uint8_t *pbuf, uint16_t size) { + HAL_PCD_EP_Receive(pdev->pData, ep_addr, pbuf, size); + return USBD_OK; +} + +/** + * @brief Returns the last transfered packet size. + * @param pdev: Device handle + * @param ep_addr: Endpoint Number + * @retval Recived Data Size + */ +uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { + return HAL_PCD_EP_GetRxCount(pdev->pData, ep_addr); +} + +/** + * @brief Delay routine for the USB Device Library + * @param Delay: Delay in ms + * @retval None + */ +void USBD_LL_Delay(uint32_t Delay) { + HAL_Delay(Delay); +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/usbd_conf.h b/ports/stm32/usbd_conf.h index 657bba67ed..e68cbd9a4b 100644 --- a/ports/stm32/usbd_conf.h +++ b/ports/stm32/usbd_conf.h @@ -1,48 +1,48 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - */ - -/** - ****************************************************************************** - * @file USB_Device/CDC_Standalone/Inc/usbd_conf.h - * @author MCD Application Team - * @version V1.0.1 - * @date 26-February-2014 - * @brief General low level driver configuration - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2014 STMicroelectronics

- * - * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.st.com/software_license_agreement_liberty_v2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ****************************************************************************** - */ - -#ifndef __USBD_CONF_H -#define __USBD_CONF_H - -#include -#include -#include -#include - -#define USBD_MAX_NUM_INTERFACES 1 -#define USBD_MAX_NUM_CONFIGURATION 1 -#define USBD_MAX_STR_DESC_SIZ 0x100 -#define USBD_SELF_POWERED 0 -#define USBD_DEBUG_LEVEL 0 - -#endif /* __USBD_CONF_H */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +/* + * This file is part of the MicroPython project, http://micropython.org/ + */ + +/** + ****************************************************************************** + * @file USB_Device/CDC_Standalone/Inc/usbd_conf.h + * @author MCD Application Team + * @version V1.0.1 + * @date 26-February-2014 + * @brief General low level driver configuration + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +#ifndef MICROPY_INCLUDED_STM32_USBD_CONF_H +#define MICROPY_INCLUDED_STM32_USBD_CONF_H + +#include +#include +#include +#include + +#define USBD_MAX_NUM_INTERFACES 1 +#define USBD_MAX_NUM_CONFIGURATION 1 +#define USBD_MAX_STR_DESC_SIZ 0x100 +#define USBD_SELF_POWERED 0 +#define USBD_DEBUG_LEVEL 0 + +#endif // MICROPY_INCLUDED_STM32_USBD_CONF_H + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ From abde0fa2267f9062b28c3c015d7662a550125cc6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 11 May 2018 23:03:52 +1000 Subject: [PATCH 635/828] stm32/usbdev: Convert files to unix line endings. Also remove trailing whitespace and convert tabs to spaces. --- ports/stm32/usbdev/class/inc/usbd_msc_bot.h | 302 ++-- ports/stm32/usbdev/class/inc/usbd_msc_data.h | 208 +-- ports/stm32/usbdev/class/inc/usbd_msc_scsi.h | 390 ++--- ports/stm32/usbdev/class/src/usbd_msc_bot.c | 814 ++++----- ports/stm32/usbdev/class/src/usbd_msc_data.c | 268 +-- ports/stm32/usbdev/class/src/usbd_msc_scsi.c | 1622 +++++++++--------- ports/stm32/usbdev/core/inc/usbd_core.h | 318 ++-- ports/stm32/usbdev/core/inc/usbd_ctlreq.h | 212 +-- ports/stm32/usbdev/core/inc/usbd_def.h | 626 +++---- ports/stm32/usbdev/core/inc/usbd_ioreq.h | 242 +-- ports/stm32/usbdev/core/src/usbd_core.c | 1104 ++++++------ ports/stm32/usbdev/core/src/usbd_ctlreq.c | 1480 ++++++++-------- ports/stm32/usbdev/core/src/usbd_ioreq.c | 472 ++--- 13 files changed, 4029 insertions(+), 4029 deletions(-) diff --git a/ports/stm32/usbdev/class/inc/usbd_msc_bot.h b/ports/stm32/usbdev/class/inc/usbd_msc_bot.h index 41f8ab5a53..4edc912fe1 100644 --- a/ports/stm32/usbdev/class/inc/usbd_msc_bot.h +++ b/ports/stm32/usbdev/class/inc/usbd_msc_bot.h @@ -1,151 +1,151 @@ -/** - ****************************************************************************** - * @file usbd_msc_bot.h - * @author MCD Application Team - * @version V2.0.0 - * @date 18-February-2014 - * @brief header for the usbd_msc_bot.c file - ****************************************************************************** - * @attention - * - *

© COPYRIGHT 2014 STMicroelectronics

- * - * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.st.com/software_license_agreement_liberty_v2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ - -#include "usbd_core.h" - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USBD_MSC_BOT_H -#define __USBD_MSC_BOT_H - -/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY - * @{ - */ - -/** @defgroup MSC_BOT - * @brief This file is the Header file for usbd_bot.c - * @{ - */ - - -/** @defgroup USBD_CORE_Exported_Defines - * @{ - */ -#define USBD_BOT_IDLE 0 /* Idle state */ -#define USBD_BOT_DATA_OUT 1 /* Data Out state */ -#define USBD_BOT_DATA_IN 2 /* Data In state */ -#define USBD_BOT_LAST_DATA_IN 3 /* Last Data In Last */ -#define USBD_BOT_SEND_DATA 4 /* Send Immediate data */ -#define USBD_BOT_NO_DATA 5 /* No data Stage */ - -#define USBD_BOT_CBW_SIGNATURE 0x43425355 -#define USBD_BOT_CSW_SIGNATURE 0x53425355 -#define USBD_BOT_CBW_LENGTH 31 -#define USBD_BOT_CSW_LENGTH 13 -#define USBD_BOT_MAX_DATA 256 - -/* CSW Status Definitions */ -#define USBD_CSW_CMD_PASSED 0x00 -#define USBD_CSW_CMD_FAILED 0x01 -#define USBD_CSW_PHASE_ERROR 0x02 - -/* BOT Status */ -#define USBD_BOT_STATUS_NORMAL 0 -#define USBD_BOT_STATUS_RECOVERY 1 -#define USBD_BOT_STATUS_ERROR 2 - - -#define USBD_DIR_IN 0 -#define USBD_DIR_OUT 1 -#define USBD_BOTH_DIR 2 - -/** - * @} - */ - -/** @defgroup MSC_CORE_Private_TypesDefinitions - * @{ - */ - -typedef struct -{ - uint32_t dSignature; - uint32_t dTag; - uint32_t dDataLength; - uint8_t bmFlags; - uint8_t bLUN; - uint8_t bCBLength; - uint8_t CB[16]; - uint8_t ReservedForAlign; -} -USBD_MSC_BOT_CBWTypeDef; - - -typedef struct -{ - uint32_t dSignature; - uint32_t dTag; - uint32_t dDataResidue; - uint8_t bStatus; - uint8_t ReservedForAlign[3]; -} -USBD_MSC_BOT_CSWTypeDef; - -/** - * @} - */ - - -/** @defgroup USBD_CORE_Exported_Types - * @{ - */ - -/** - * @} - */ -/** @defgroup USBD_CORE_Exported_FunctionsPrototypes - * @{ - */ -void MSC_BOT_Init (USBD_HandleTypeDef *pdev); -void MSC_BOT_Reset (USBD_HandleTypeDef *pdev); -void MSC_BOT_DeInit (USBD_HandleTypeDef *pdev); -void MSC_BOT_DataIn (USBD_HandleTypeDef *pdev, - uint8_t epnum); - -void MSC_BOT_DataOut (USBD_HandleTypeDef *pdev, - uint8_t epnum); - -void MSC_BOT_SendCSW (USBD_HandleTypeDef *pdev, - uint8_t CSW_Status); - -void MSC_BOT_CplClrFeature (USBD_HandleTypeDef *pdev, - uint8_t epnum); -/** - * @} - */ - -#endif /* __USBD_MSC_BOT_H */ -/** - * @} - */ - -/** -* @} -*/ -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ - +/** + ****************************************************************************** + * @file usbd_msc_bot.h + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief header for the usbd_msc_bot.c file + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ + +#include "usbd_core.h" + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_MSC_BOT_H +#define __USBD_MSC_BOT_H + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup MSC_BOT + * @brief This file is the Header file for usbd_bot.c + * @{ + */ + + +/** @defgroup USBD_CORE_Exported_Defines + * @{ + */ +#define USBD_BOT_IDLE 0 /* Idle state */ +#define USBD_BOT_DATA_OUT 1 /* Data Out state */ +#define USBD_BOT_DATA_IN 2 /* Data In state */ +#define USBD_BOT_LAST_DATA_IN 3 /* Last Data In Last */ +#define USBD_BOT_SEND_DATA 4 /* Send Immediate data */ +#define USBD_BOT_NO_DATA 5 /* No data Stage */ + +#define USBD_BOT_CBW_SIGNATURE 0x43425355 +#define USBD_BOT_CSW_SIGNATURE 0x53425355 +#define USBD_BOT_CBW_LENGTH 31 +#define USBD_BOT_CSW_LENGTH 13 +#define USBD_BOT_MAX_DATA 256 + +/* CSW Status Definitions */ +#define USBD_CSW_CMD_PASSED 0x00 +#define USBD_CSW_CMD_FAILED 0x01 +#define USBD_CSW_PHASE_ERROR 0x02 + +/* BOT Status */ +#define USBD_BOT_STATUS_NORMAL 0 +#define USBD_BOT_STATUS_RECOVERY 1 +#define USBD_BOT_STATUS_ERROR 2 + + +#define USBD_DIR_IN 0 +#define USBD_DIR_OUT 1 +#define USBD_BOTH_DIR 2 + +/** + * @} + */ + +/** @defgroup MSC_CORE_Private_TypesDefinitions + * @{ + */ + +typedef struct +{ + uint32_t dSignature; + uint32_t dTag; + uint32_t dDataLength; + uint8_t bmFlags; + uint8_t bLUN; + uint8_t bCBLength; + uint8_t CB[16]; + uint8_t ReservedForAlign; +} +USBD_MSC_BOT_CBWTypeDef; + + +typedef struct +{ + uint32_t dSignature; + uint32_t dTag; + uint32_t dDataResidue; + uint8_t bStatus; + uint8_t ReservedForAlign[3]; +} +USBD_MSC_BOT_CSWTypeDef; + +/** + * @} + */ + + +/** @defgroup USBD_CORE_Exported_Types + * @{ + */ + +/** + * @} + */ +/** @defgroup USBD_CORE_Exported_FunctionsPrototypes + * @{ + */ +void MSC_BOT_Init (USBD_HandleTypeDef *pdev); +void MSC_BOT_Reset (USBD_HandleTypeDef *pdev); +void MSC_BOT_DeInit (USBD_HandleTypeDef *pdev); +void MSC_BOT_DataIn (USBD_HandleTypeDef *pdev, + uint8_t epnum); + +void MSC_BOT_DataOut (USBD_HandleTypeDef *pdev, + uint8_t epnum); + +void MSC_BOT_SendCSW (USBD_HandleTypeDef *pdev, + uint8_t CSW_Status); + +void MSC_BOT_CplClrFeature (USBD_HandleTypeDef *pdev, + uint8_t epnum); +/** + * @} + */ + +#endif /* __USBD_MSC_BOT_H */ +/** + * @} + */ + +/** +* @} +*/ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/ports/stm32/usbdev/class/inc/usbd_msc_data.h b/ports/stm32/usbdev/class/inc/usbd_msc_data.h index f468267f43..afd39e4f09 100644 --- a/ports/stm32/usbdev/class/inc/usbd_msc_data.h +++ b/ports/stm32/usbdev/class/inc/usbd_msc_data.h @@ -1,104 +1,104 @@ -/** - ****************************************************************************** - * @file usbd_msc_data.h - * @author MCD Application Team - * @version V2.0.0 - * @date 18-February-2014 - * @brief header for the usbd_msc_data.c file - ****************************************************************************** - * @attention - * - *

© COPYRIGHT 2014 STMicroelectronics

- * - * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.st.com/software_license_agreement_liberty_v2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ - -#ifndef _USBD_MSC_DATA_H_ -#define _USBD_MSC_DATA_H_ - -/* Includes ------------------------------------------------------------------*/ -#include "usbd_conf.h" - -/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY - * @{ - */ - -/** @defgroup USB_INFO - * @brief general defines for the usb device library file - * @{ - */ - -/** @defgroup USB_INFO_Exported_Defines - * @{ - */ -#define MODE_SENSE6_LEN 8 -#define MODE_SENSE10_LEN 8 -#define LENGTH_INQUIRY_PAGE00 7 -#define LENGTH_FORMAT_CAPACITIES 20 - -/** - * @} - */ - - -/** @defgroup USBD_INFO_Exported_TypesDefinitions - * @{ - */ -/** - * @} - */ - - - -/** @defgroup USBD_INFO_Exported_Macros - * @{ - */ - -/** - * @} - */ - -/** @defgroup USBD_INFO_Exported_Variables - * @{ - */ -extern const uint8_t MSC_Page00_Inquiry_Data[]; -extern const uint8_t MSC_Mode_Sense6_data[]; -extern const uint8_t MSC_Mode_Sense10_data[] ; - -/** - * @} - */ - -/** @defgroup USBD_INFO_Exported_FunctionsPrototype - * @{ - */ - -/** - * @} - */ - -#endif /* _USBD_MSC_DATA_H_ */ - -/** - * @} - */ - -/** -* @} -*/ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +/** + ****************************************************************************** + * @file usbd_msc_data.h + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief header for the usbd_msc_data.c file + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ + +#ifndef _USBD_MSC_DATA_H_ +#define _USBD_MSC_DATA_H_ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_conf.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USB_INFO + * @brief general defines for the usb device library file + * @{ + */ + +/** @defgroup USB_INFO_Exported_Defines + * @{ + */ +#define MODE_SENSE6_LEN 8 +#define MODE_SENSE10_LEN 8 +#define LENGTH_INQUIRY_PAGE00 7 +#define LENGTH_FORMAT_CAPACITIES 20 + +/** + * @} + */ + + +/** @defgroup USBD_INFO_Exported_TypesDefinitions + * @{ + */ +/** + * @} + */ + + + +/** @defgroup USBD_INFO_Exported_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_INFO_Exported_Variables + * @{ + */ +extern const uint8_t MSC_Page00_Inquiry_Data[]; +extern const uint8_t MSC_Mode_Sense6_data[]; +extern const uint8_t MSC_Mode_Sense10_data[] ; + +/** + * @} + */ + +/** @defgroup USBD_INFO_Exported_FunctionsPrototype + * @{ + */ + +/** + * @} + */ + +#endif /* _USBD_MSC_DATA_H_ */ + +/** + * @} + */ + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/usbdev/class/inc/usbd_msc_scsi.h b/ports/stm32/usbdev/class/inc/usbd_msc_scsi.h index 34f059ee5d..b657cead09 100644 --- a/ports/stm32/usbdev/class/inc/usbd_msc_scsi.h +++ b/ports/stm32/usbdev/class/inc/usbd_msc_scsi.h @@ -1,195 +1,195 @@ -/** - ****************************************************************************** - * @file usbd_msc_scsi.h - * @author MCD Application Team - * @version V2.0.0 - * @date 18-February-2014 - * @brief header for the usbd_msc_scsi.c file - ****************************************************************************** - * @attention - * - *

© COPYRIGHT 2014 STMicroelectronics

- * - * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.st.com/software_license_agreement_liberty_v2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USBD_MSC_SCSI_H -#define __USBD_MSC_SCSI_H - -/* Includes ------------------------------------------------------------------*/ -#include "usbd_def.h" - -/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY - * @{ - */ - -/** @defgroup USBD_SCSI - * @brief header file for the storage disk file - * @{ - */ - -/** @defgroup USBD_SCSI_Exported_Defines - * @{ - */ - -#define SENSE_LIST_DEEPTH 4 - -/* SCSI Commands */ -#define SCSI_FORMAT_UNIT 0x04 -#define SCSI_INQUIRY 0x12 -#define SCSI_MODE_SELECT6 0x15 -#define SCSI_MODE_SELECT10 0x55 -#define SCSI_MODE_SENSE6 0x1A -#define SCSI_MODE_SENSE10 0x5A -#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1E -#define SCSI_SYNCHRONIZE_CACHE10 0x35 -#define SCSI_SYNCHRONIZE_CACHE16 0x91 -#define SCSI_READ6 0x08 -#define SCSI_READ10 0x28 -#define SCSI_READ12 0xA8 -#define SCSI_READ16 0x88 - -#define SCSI_READ_CAPACITY10 0x25 -#define SCSI_READ_CAPACITY16 0x9E - -#define SCSI_REQUEST_SENSE 0x03 -#define SCSI_START_STOP_UNIT 0x1B -#define SCSI_TEST_UNIT_READY 0x00 -#define SCSI_WRITE6 0x0A -#define SCSI_WRITE10 0x2A -#define SCSI_WRITE12 0xAA -#define SCSI_WRITE16 0x8A - -#define SCSI_VERIFY10 0x2F -#define SCSI_VERIFY12 0xAF -#define SCSI_VERIFY16 0x8F - -#define SCSI_SEND_DIAGNOSTIC 0x1D -#define SCSI_READ_FORMAT_CAPACITIES 0x23 - -#define NO_SENSE 0 -#define RECOVERED_ERROR 1 -#define NOT_READY 2 -#define MEDIUM_ERROR 3 -#define HARDWARE_ERROR 4 -#define ILLEGAL_REQUEST 5 -#define UNIT_ATTENTION 6 -#define DATA_PROTECT 7 -#define BLANK_CHECK 8 -#define VENDOR_SPECIFIC 9 -#define COPY_ABORTED 10 -#define ABORTED_COMMAND 11 -#define VOLUME_OVERFLOW 13 -#define MISCOMPARE 14 - - -#define INVALID_CDB 0x20 -#define INVALID_FIELED_IN_COMMAND 0x24 -#define PARAMETER_LIST_LENGTH_ERROR 0x1A -#define INVALID_FIELD_IN_PARAMETER_LIST 0x26 -#define ADDRESS_OUT_OF_RANGE 0x21 -#define MEDIUM_NOT_PRESENT 0x3A -#define MEDIUM_HAVE_CHANGED 0x28 -#define WRITE_PROTECTED 0x27 -#define UNRECOVERED_READ_ERROR 0x11 -#define WRITE_FAULT 0x03 - -#define READ_FORMAT_CAPACITY_DATA_LEN 0x0C -#define READ_CAPACITY10_DATA_LEN 0x08 -#define MODE_SENSE10_DATA_LEN 0x08 -#define MODE_SENSE6_DATA_LEN 0x04 -#define REQUEST_SENSE_DATA_LEN 0x12 -#define STANDARD_INQUIRY_DATA_LEN 0x24 -#define BLKVFY 0x04 - -extern uint8_t Page00_Inquiry_Data[]; -extern uint8_t Standard_Inquiry_Data[]; -extern uint8_t Standard_Inquiry_Data2[]; -extern uint8_t Mode_Sense6_data[]; -extern uint8_t Mode_Sense10_data[]; -extern uint8_t Scsi_Sense_Data[]; -extern uint8_t ReadCapacity10_Data[]; -extern uint8_t ReadFormatCapacity_Data []; -/** - * @} - */ - - -/** @defgroup USBD_SCSI_Exported_TypesDefinitions - * @{ - */ - -typedef struct _SENSE_ITEM { - char Skey; - union { - struct _ASCs { - char ASC; - char ASCQ; - }b; - unsigned int ASC; - char *pData; - } w; -} USBD_SCSI_SenseTypeDef; -/** - * @} - */ - -/** @defgroup USBD_SCSI_Exported_Macros - * @{ - */ - -/** - * @} - */ - -/** @defgroup USBD_SCSI_Exported_Variables - * @{ - */ - -/** - * @} - */ -/** @defgroup USBD_SCSI_Exported_FunctionsPrototype - * @{ - */ -int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev, - uint8_t lun, - uint8_t *cmd); - -void SCSI_SenseCode(USBD_HandleTypeDef *pdev, - uint8_t lun, - uint8_t sKey, - uint8_t ASC); - -/** - * @} - */ - -#endif /* __USBD_MSC_SCSI_H */ -/** - * @} - */ - -/** - * @} - */ - -/** -* @} -*/ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ - +/** + ****************************************************************************** + * @file usbd_msc_scsi.h + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief header for the usbd_msc_scsi.c file + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_MSC_SCSI_H +#define __USBD_MSC_SCSI_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_def.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USBD_SCSI + * @brief header file for the storage disk file + * @{ + */ + +/** @defgroup USBD_SCSI_Exported_Defines + * @{ + */ + +#define SENSE_LIST_DEEPTH 4 + +/* SCSI Commands */ +#define SCSI_FORMAT_UNIT 0x04 +#define SCSI_INQUIRY 0x12 +#define SCSI_MODE_SELECT6 0x15 +#define SCSI_MODE_SELECT10 0x55 +#define SCSI_MODE_SENSE6 0x1A +#define SCSI_MODE_SENSE10 0x5A +#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1E +#define SCSI_SYNCHRONIZE_CACHE10 0x35 +#define SCSI_SYNCHRONIZE_CACHE16 0x91 +#define SCSI_READ6 0x08 +#define SCSI_READ10 0x28 +#define SCSI_READ12 0xA8 +#define SCSI_READ16 0x88 + +#define SCSI_READ_CAPACITY10 0x25 +#define SCSI_READ_CAPACITY16 0x9E + +#define SCSI_REQUEST_SENSE 0x03 +#define SCSI_START_STOP_UNIT 0x1B +#define SCSI_TEST_UNIT_READY 0x00 +#define SCSI_WRITE6 0x0A +#define SCSI_WRITE10 0x2A +#define SCSI_WRITE12 0xAA +#define SCSI_WRITE16 0x8A + +#define SCSI_VERIFY10 0x2F +#define SCSI_VERIFY12 0xAF +#define SCSI_VERIFY16 0x8F + +#define SCSI_SEND_DIAGNOSTIC 0x1D +#define SCSI_READ_FORMAT_CAPACITIES 0x23 + +#define NO_SENSE 0 +#define RECOVERED_ERROR 1 +#define NOT_READY 2 +#define MEDIUM_ERROR 3 +#define HARDWARE_ERROR 4 +#define ILLEGAL_REQUEST 5 +#define UNIT_ATTENTION 6 +#define DATA_PROTECT 7 +#define BLANK_CHECK 8 +#define VENDOR_SPECIFIC 9 +#define COPY_ABORTED 10 +#define ABORTED_COMMAND 11 +#define VOLUME_OVERFLOW 13 +#define MISCOMPARE 14 + + +#define INVALID_CDB 0x20 +#define INVALID_FIELED_IN_COMMAND 0x24 +#define PARAMETER_LIST_LENGTH_ERROR 0x1A +#define INVALID_FIELD_IN_PARAMETER_LIST 0x26 +#define ADDRESS_OUT_OF_RANGE 0x21 +#define MEDIUM_NOT_PRESENT 0x3A +#define MEDIUM_HAVE_CHANGED 0x28 +#define WRITE_PROTECTED 0x27 +#define UNRECOVERED_READ_ERROR 0x11 +#define WRITE_FAULT 0x03 + +#define READ_FORMAT_CAPACITY_DATA_LEN 0x0C +#define READ_CAPACITY10_DATA_LEN 0x08 +#define MODE_SENSE10_DATA_LEN 0x08 +#define MODE_SENSE6_DATA_LEN 0x04 +#define REQUEST_SENSE_DATA_LEN 0x12 +#define STANDARD_INQUIRY_DATA_LEN 0x24 +#define BLKVFY 0x04 + +extern uint8_t Page00_Inquiry_Data[]; +extern uint8_t Standard_Inquiry_Data[]; +extern uint8_t Standard_Inquiry_Data2[]; +extern uint8_t Mode_Sense6_data[]; +extern uint8_t Mode_Sense10_data[]; +extern uint8_t Scsi_Sense_Data[]; +extern uint8_t ReadCapacity10_Data[]; +extern uint8_t ReadFormatCapacity_Data []; +/** + * @} + */ + + +/** @defgroup USBD_SCSI_Exported_TypesDefinitions + * @{ + */ + +typedef struct _SENSE_ITEM { + char Skey; + union { + struct _ASCs { + char ASC; + char ASCQ; + }b; + unsigned int ASC; + char *pData; + } w; +} USBD_SCSI_SenseTypeDef; +/** + * @} + */ + +/** @defgroup USBD_SCSI_Exported_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_SCSI_Exported_Variables + * @{ + */ + +/** + * @} + */ +/** @defgroup USBD_SCSI_Exported_FunctionsPrototype + * @{ + */ +int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev, + uint8_t lun, + uint8_t *cmd); + +void SCSI_SenseCode(USBD_HandleTypeDef *pdev, + uint8_t lun, + uint8_t sKey, + uint8_t ASC); + +/** + * @} + */ + +#endif /* __USBD_MSC_SCSI_H */ +/** + * @} + */ + +/** + * @} + */ + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/ports/stm32/usbdev/class/src/usbd_msc_bot.c b/ports/stm32/usbdev/class/src/usbd_msc_bot.c index 2fccd9e082..d20f7a8dc0 100644 --- a/ports/stm32/usbdev/class/src/usbd_msc_bot.c +++ b/ports/stm32/usbdev/class/src/usbd_msc_bot.c @@ -1,407 +1,407 @@ -/** - ****************************************************************************** - * @file usbd_msc_bot.c - * @author MCD Application Team - * @version V2.0.0 - * @date 18-February-2014 - * @brief This file provides all the BOT protocol core functions. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT 2014 STMicroelectronics

- * - * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.st.com/software_license_agreement_liberty_v2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ****************************************************************************** - */ - -/* Includes ------------------------------------------------------------------*/ -#include "usbd_msc_bot.h" -#include "usbd_msc_scsi.h" -#include "usbd_cdc_msc_hid.h" -#include "usbd_ioreq.h" - -/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY - * @{ - */ - - -/** @defgroup MSC_BOT - * @brief BOT protocol module - * @{ - */ - -/** @defgroup MSC_BOT_Private_TypesDefinitions - * @{ - */ -/** - * @} - */ - - -/** @defgroup MSC_BOT_Private_Defines - * @{ - */ - -/** - * @} - */ - - -/** @defgroup MSC_BOT_Private_Macros - * @{ - */ -/** - * @} - */ - - -/** @defgroup MSC_BOT_Private_Variables - * @{ - */ - -/** - * @} - */ - - -/** @defgroup MSC_BOT_Private_FunctionPrototypes - * @{ - */ -static void MSC_BOT_CBW_Decode (USBD_HandleTypeDef *pdev); - -static void MSC_BOT_SendData (USBD_HandleTypeDef *pdev, - uint8_t* pbuf, - uint16_t len); - -static void MSC_BOT_Abort(USBD_HandleTypeDef *pdev); -/** - * @} - */ - - -/** @defgroup MSC_BOT_Private_Functions - * @{ - */ - - - -/** -* @brief MSC_BOT_Init -* Initialize the BOT Process -* @param pdev: device instance -* @retval None -*/ -void MSC_BOT_Init (USBD_HandleTypeDef *pdev) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - hmsc->bot_state = USBD_BOT_IDLE; - hmsc->bot_status = USBD_BOT_STATUS_NORMAL; - - hmsc->scsi_sense_tail = 0; - hmsc->scsi_sense_head = 0; - - hmsc->bdev_ops->Init(0); - - USBD_LL_FlushEP(pdev, MSC_OUT_EP); - USBD_LL_FlushEP(pdev, MSC_IN_EP); - - /* Prapare EP to Receive First BOT Cmd */ - USBD_LL_PrepareReceive (pdev, - MSC_OUT_EP, - (uint8_t *)&hmsc->cbw, - USBD_BOT_CBW_LENGTH); -} - -/** -* @brief MSC_BOT_Reset -* Reset the BOT Machine -* @param pdev: device instance -* @retval None -*/ -void MSC_BOT_Reset (USBD_HandleTypeDef *pdev) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - hmsc->bot_state = USBD_BOT_IDLE; - hmsc->bot_status = USBD_BOT_STATUS_RECOVERY; - - /* Prapare EP to Receive First BOT Cmd */ - USBD_LL_PrepareReceive (pdev, - MSC_OUT_EP, - (uint8_t *)&hmsc->cbw, - USBD_BOT_CBW_LENGTH); -} - -/** -* @brief MSC_BOT_DeInit -* Uninitialize the BOT Machine -* @param pdev: device instance -* @retval None -*/ -void MSC_BOT_DeInit (USBD_HandleTypeDef *pdev) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - hmsc->bot_state = USBD_BOT_IDLE; -} - -/** -* @brief MSC_BOT_DataIn -* Handle BOT IN data stage -* @param pdev: device instance -* @param epnum: endpoint index -* @retval None -*/ -void MSC_BOT_DataIn (USBD_HandleTypeDef *pdev, - uint8_t epnum) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - switch (hmsc->bot_state) - { - case USBD_BOT_DATA_IN: - if(SCSI_ProcessCmd(pdev, - hmsc->cbw.bLUN, - &hmsc->cbw.CB[0]) < 0) - { - MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED); - } - break; - - case USBD_BOT_SEND_DATA: - case USBD_BOT_LAST_DATA_IN: - MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_PASSED); - - break; - - default: - break; - } -} -/** -* @brief MSC_BOT_DataOut -* Proccess MSC OUT data -* @param pdev: device instance -* @param epnum: endpoint index -* @retval None -*/ -void MSC_BOT_DataOut (USBD_HandleTypeDef *pdev, - uint8_t epnum) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - switch (hmsc->bot_state) - { - case USBD_BOT_IDLE: - MSC_BOT_CBW_Decode(pdev); - break; - - case USBD_BOT_DATA_OUT: - - if(SCSI_ProcessCmd(pdev, - hmsc->cbw.bLUN, - &hmsc->cbw.CB[0]) < 0) - { - MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED); - } - - break; - - default: - break; - } -} - -/** -* @brief MSC_BOT_CBW_Decode -* Decode the CBW command and set the BOT state machine accordingtly -* @param pdev: device instance -* @retval None -*/ -static void MSC_BOT_CBW_Decode (USBD_HandleTypeDef *pdev) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - hmsc->csw.dTag = hmsc->cbw.dTag; - hmsc->csw.dDataResidue = hmsc->cbw.dDataLength; - - if ((USBD_LL_GetRxDataSize (pdev ,MSC_OUT_EP) != USBD_BOT_CBW_LENGTH) || - (hmsc->cbw.dSignature != USBD_BOT_CBW_SIGNATURE)|| - (hmsc->cbw.bLUN > 1) || - (hmsc->cbw.bCBLength < 1) || - (hmsc->cbw.bCBLength > 16)) - { - - SCSI_SenseCode(pdev, - hmsc->cbw.bLUN, - ILLEGAL_REQUEST, - INVALID_CDB); - - hmsc->bot_status = USBD_BOT_STATUS_ERROR; - MSC_BOT_Abort(pdev); - - } - else - { - if(SCSI_ProcessCmd(pdev, - hmsc->cbw.bLUN, - &hmsc->cbw.CB[0]) < 0) - { - if(hmsc->bot_state == USBD_BOT_NO_DATA) - { - MSC_BOT_SendCSW (pdev, - USBD_CSW_CMD_FAILED); - } - else - { - MSC_BOT_Abort(pdev); - } - } - /*Burst xfer handled internally*/ - else if ((hmsc->bot_state != USBD_BOT_DATA_IN) && - (hmsc->bot_state != USBD_BOT_DATA_OUT) && - (hmsc->bot_state != USBD_BOT_LAST_DATA_IN)) - { - if (hmsc->bot_data_length > 0) - { - MSC_BOT_SendData(pdev, - hmsc->bot_data, - hmsc->bot_data_length); - } - else if (hmsc->bot_data_length == 0) - { - MSC_BOT_SendCSW (pdev, - USBD_CSW_CMD_PASSED); - } - } - } -} - -/** -* @brief MSC_BOT_SendData -* Send the requested data -* @param pdev: device instance -* @param buf: pointer to data buffer -* @param len: Data Length -* @retval None -*/ -static void MSC_BOT_SendData(USBD_HandleTypeDef *pdev, - uint8_t* buf, - uint16_t len) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - len = MIN (hmsc->cbw.dDataLength, len); - hmsc->csw.dDataResidue -= len; - hmsc->csw.bStatus = USBD_CSW_CMD_PASSED; - hmsc->bot_state = USBD_BOT_SEND_DATA; - - USBD_LL_Transmit (pdev, MSC_IN_EP, buf, len); -} - -/** -* @brief MSC_BOT_SendCSW -* Send the Command Status Wrapper -* @param pdev: device instance -* @param status : CSW status -* @retval None -*/ -void MSC_BOT_SendCSW (USBD_HandleTypeDef *pdev, - uint8_t CSW_Status) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - hmsc->csw.dSignature = USBD_BOT_CSW_SIGNATURE; - hmsc->csw.bStatus = CSW_Status; - hmsc->bot_state = USBD_BOT_IDLE; - - USBD_LL_Transmit (pdev, - MSC_IN_EP, - (uint8_t *)&hmsc->csw, - USBD_BOT_CSW_LENGTH); - - /* Prapare EP to Receive next Cmd */ - USBD_LL_PrepareReceive (pdev, - MSC_OUT_EP, - (uint8_t *)&hmsc->cbw, - USBD_BOT_CBW_LENGTH); - -} - -/** -* @brief MSC_BOT_Abort -* Abort the current transfer -* @param pdev: device instance -* @retval status -*/ - -static void MSC_BOT_Abort (USBD_HandleTypeDef *pdev) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - if ((hmsc->cbw.bmFlags == 0) && - (hmsc->cbw.dDataLength != 0) && - (hmsc->bot_status == USBD_BOT_STATUS_NORMAL) ) - { - USBD_LL_StallEP(pdev, MSC_OUT_EP ); - } - USBD_LL_StallEP(pdev, MSC_IN_EP); - - if(hmsc->bot_status == USBD_BOT_STATUS_ERROR) - { - USBD_LL_PrepareReceive (pdev, - MSC_OUT_EP, - (uint8_t *)&hmsc->cbw, - USBD_BOT_CBW_LENGTH); - } -} - -/** -* @brief MSC_BOT_CplClrFeature -* Complete the clear feature request -* @param pdev: device instance -* @param epnum: endpoint index -* @retval None -*/ - -void MSC_BOT_CplClrFeature (USBD_HandleTypeDef *pdev, uint8_t epnum) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - if(hmsc->bot_status == USBD_BOT_STATUS_ERROR )/* Bad CBW Signature */ - { - USBD_LL_StallEP(pdev, MSC_IN_EP); - hmsc->bot_status = USBD_BOT_STATUS_NORMAL; - } - else if(((epnum & 0x80) == 0x80) && ( hmsc->bot_status != USBD_BOT_STATUS_RECOVERY)) - { - MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED); - } - -} -/** - * @} - */ - - -/** - * @} - */ - - -/** - * @} - */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +/** + ****************************************************************************** + * @file usbd_msc_bot.c + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief This file provides all the BOT protocol core functions. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_msc_bot.h" +#include "usbd_msc_scsi.h" +#include "usbd_cdc_msc_hid.h" +#include "usbd_ioreq.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup MSC_BOT + * @brief BOT protocol module + * @{ + */ + +/** @defgroup MSC_BOT_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_BOT_Private_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup MSC_BOT_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_BOT_Private_Variables + * @{ + */ + +/** + * @} + */ + + +/** @defgroup MSC_BOT_Private_FunctionPrototypes + * @{ + */ +static void MSC_BOT_CBW_Decode (USBD_HandleTypeDef *pdev); + +static void MSC_BOT_SendData (USBD_HandleTypeDef *pdev, + uint8_t* pbuf, + uint16_t len); + +static void MSC_BOT_Abort(USBD_HandleTypeDef *pdev); +/** + * @} + */ + + +/** @defgroup MSC_BOT_Private_Functions + * @{ + */ + + + +/** +* @brief MSC_BOT_Init +* Initialize the BOT Process +* @param pdev: device instance +* @retval None +*/ +void MSC_BOT_Init (USBD_HandleTypeDef *pdev) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + hmsc->bot_state = USBD_BOT_IDLE; + hmsc->bot_status = USBD_BOT_STATUS_NORMAL; + + hmsc->scsi_sense_tail = 0; + hmsc->scsi_sense_head = 0; + + hmsc->bdev_ops->Init(0); + + USBD_LL_FlushEP(pdev, MSC_OUT_EP); + USBD_LL_FlushEP(pdev, MSC_IN_EP); + + /* Prapare EP to Receive First BOT Cmd */ + USBD_LL_PrepareReceive (pdev, + MSC_OUT_EP, + (uint8_t *)&hmsc->cbw, + USBD_BOT_CBW_LENGTH); +} + +/** +* @brief MSC_BOT_Reset +* Reset the BOT Machine +* @param pdev: device instance +* @retval None +*/ +void MSC_BOT_Reset (USBD_HandleTypeDef *pdev) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + hmsc->bot_state = USBD_BOT_IDLE; + hmsc->bot_status = USBD_BOT_STATUS_RECOVERY; + + /* Prapare EP to Receive First BOT Cmd */ + USBD_LL_PrepareReceive (pdev, + MSC_OUT_EP, + (uint8_t *)&hmsc->cbw, + USBD_BOT_CBW_LENGTH); +} + +/** +* @brief MSC_BOT_DeInit +* Uninitialize the BOT Machine +* @param pdev: device instance +* @retval None +*/ +void MSC_BOT_DeInit (USBD_HandleTypeDef *pdev) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + hmsc->bot_state = USBD_BOT_IDLE; +} + +/** +* @brief MSC_BOT_DataIn +* Handle BOT IN data stage +* @param pdev: device instance +* @param epnum: endpoint index +* @retval None +*/ +void MSC_BOT_DataIn (USBD_HandleTypeDef *pdev, + uint8_t epnum) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + switch (hmsc->bot_state) + { + case USBD_BOT_DATA_IN: + if(SCSI_ProcessCmd(pdev, + hmsc->cbw.bLUN, + &hmsc->cbw.CB[0]) < 0) + { + MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED); + } + break; + + case USBD_BOT_SEND_DATA: + case USBD_BOT_LAST_DATA_IN: + MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_PASSED); + + break; + + default: + break; + } +} +/** +* @brief MSC_BOT_DataOut +* Proccess MSC OUT data +* @param pdev: device instance +* @param epnum: endpoint index +* @retval None +*/ +void MSC_BOT_DataOut (USBD_HandleTypeDef *pdev, + uint8_t epnum) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + switch (hmsc->bot_state) + { + case USBD_BOT_IDLE: + MSC_BOT_CBW_Decode(pdev); + break; + + case USBD_BOT_DATA_OUT: + + if(SCSI_ProcessCmd(pdev, + hmsc->cbw.bLUN, + &hmsc->cbw.CB[0]) < 0) + { + MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED); + } + + break; + + default: + break; + } +} + +/** +* @brief MSC_BOT_CBW_Decode +* Decode the CBW command and set the BOT state machine accordingtly +* @param pdev: device instance +* @retval None +*/ +static void MSC_BOT_CBW_Decode (USBD_HandleTypeDef *pdev) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + hmsc->csw.dTag = hmsc->cbw.dTag; + hmsc->csw.dDataResidue = hmsc->cbw.dDataLength; + + if ((USBD_LL_GetRxDataSize (pdev ,MSC_OUT_EP) != USBD_BOT_CBW_LENGTH) || + (hmsc->cbw.dSignature != USBD_BOT_CBW_SIGNATURE)|| + (hmsc->cbw.bLUN > 1) || + (hmsc->cbw.bCBLength < 1) || + (hmsc->cbw.bCBLength > 16)) + { + + SCSI_SenseCode(pdev, + hmsc->cbw.bLUN, + ILLEGAL_REQUEST, + INVALID_CDB); + + hmsc->bot_status = USBD_BOT_STATUS_ERROR; + MSC_BOT_Abort(pdev); + + } + else + { + if(SCSI_ProcessCmd(pdev, + hmsc->cbw.bLUN, + &hmsc->cbw.CB[0]) < 0) + { + if(hmsc->bot_state == USBD_BOT_NO_DATA) + { + MSC_BOT_SendCSW (pdev, + USBD_CSW_CMD_FAILED); + } + else + { + MSC_BOT_Abort(pdev); + } + } + /*Burst xfer handled internally*/ + else if ((hmsc->bot_state != USBD_BOT_DATA_IN) && + (hmsc->bot_state != USBD_BOT_DATA_OUT) && + (hmsc->bot_state != USBD_BOT_LAST_DATA_IN)) + { + if (hmsc->bot_data_length > 0) + { + MSC_BOT_SendData(pdev, + hmsc->bot_data, + hmsc->bot_data_length); + } + else if (hmsc->bot_data_length == 0) + { + MSC_BOT_SendCSW (pdev, + USBD_CSW_CMD_PASSED); + } + } + } +} + +/** +* @brief MSC_BOT_SendData +* Send the requested data +* @param pdev: device instance +* @param buf: pointer to data buffer +* @param len: Data Length +* @retval None +*/ +static void MSC_BOT_SendData(USBD_HandleTypeDef *pdev, + uint8_t* buf, + uint16_t len) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + len = MIN (hmsc->cbw.dDataLength, len); + hmsc->csw.dDataResidue -= len; + hmsc->csw.bStatus = USBD_CSW_CMD_PASSED; + hmsc->bot_state = USBD_BOT_SEND_DATA; + + USBD_LL_Transmit (pdev, MSC_IN_EP, buf, len); +} + +/** +* @brief MSC_BOT_SendCSW +* Send the Command Status Wrapper +* @param pdev: device instance +* @param status : CSW status +* @retval None +*/ +void MSC_BOT_SendCSW (USBD_HandleTypeDef *pdev, + uint8_t CSW_Status) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + hmsc->csw.dSignature = USBD_BOT_CSW_SIGNATURE; + hmsc->csw.bStatus = CSW_Status; + hmsc->bot_state = USBD_BOT_IDLE; + + USBD_LL_Transmit (pdev, + MSC_IN_EP, + (uint8_t *)&hmsc->csw, + USBD_BOT_CSW_LENGTH); + + /* Prapare EP to Receive next Cmd */ + USBD_LL_PrepareReceive (pdev, + MSC_OUT_EP, + (uint8_t *)&hmsc->cbw, + USBD_BOT_CBW_LENGTH); + +} + +/** +* @brief MSC_BOT_Abort +* Abort the current transfer +* @param pdev: device instance +* @retval status +*/ + +static void MSC_BOT_Abort (USBD_HandleTypeDef *pdev) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + if ((hmsc->cbw.bmFlags == 0) && + (hmsc->cbw.dDataLength != 0) && + (hmsc->bot_status == USBD_BOT_STATUS_NORMAL) ) + { + USBD_LL_StallEP(pdev, MSC_OUT_EP ); + } + USBD_LL_StallEP(pdev, MSC_IN_EP); + + if(hmsc->bot_status == USBD_BOT_STATUS_ERROR) + { + USBD_LL_PrepareReceive (pdev, + MSC_OUT_EP, + (uint8_t *)&hmsc->cbw, + USBD_BOT_CBW_LENGTH); + } +} + +/** +* @brief MSC_BOT_CplClrFeature +* Complete the clear feature request +* @param pdev: device instance +* @param epnum: endpoint index +* @retval None +*/ + +void MSC_BOT_CplClrFeature (USBD_HandleTypeDef *pdev, uint8_t epnum) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + if(hmsc->bot_status == USBD_BOT_STATUS_ERROR )/* Bad CBW Signature */ + { + USBD_LL_StallEP(pdev, MSC_IN_EP); + hmsc->bot_status = USBD_BOT_STATUS_NORMAL; + } + else if(((epnum & 0x80) == 0x80) && ( hmsc->bot_status != USBD_BOT_STATUS_RECOVERY)) + { + MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED); + } + +} +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/usbdev/class/src/usbd_msc_data.c b/ports/stm32/usbdev/class/src/usbd_msc_data.c index 4d72bd5fce..96740a3a4f 100644 --- a/ports/stm32/usbdev/class/src/usbd_msc_data.c +++ b/ports/stm32/usbdev/class/src/usbd_msc_data.c @@ -1,134 +1,134 @@ -/** - ****************************************************************************** - * @file usbd_msc_data.c - * @author MCD Application Team - * @version V2.0.0 - * @date 18-February-2014 - * @brief This file provides all the vital inquiry pages and sense data. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT 2014 STMicroelectronics

- * - * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.st.com/software_license_agreement_liberty_v2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ****************************************************************************** - */ - -/* Includes ------------------------------------------------------------------*/ -#include "usbd_msc_data.h" - - -/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY - * @{ - */ - - -/** @defgroup MSC_DATA - * @brief Mass storage info/data module - * @{ - */ - -/** @defgroup MSC_DATA_Private_TypesDefinitions - * @{ - */ -/** - * @} - */ - - -/** @defgroup MSC_DATA_Private_Defines - * @{ - */ -/** - * @} - */ - - -/** @defgroup MSC_DATA_Private_Macros - * @{ - */ -/** - * @} - */ - - -/** @defgroup MSC_DATA_Private_Variables - * @{ - */ - - -/* USB Mass storage Page 0 Inquiry Data */ -const uint8_t MSC_Page00_Inquiry_Data[] = {//7 - 0x00, - 0x00, - 0x00, - (LENGTH_INQUIRY_PAGE00 - 4), - 0x00, - 0x80, - 0x83 -}; -/* USB Mass storage sense 6 Data */ -const uint8_t MSC_Mode_Sense6_data[] = { - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00 -}; -/* USB Mass storage sense 10 Data */ -const uint8_t MSC_Mode_Sense10_data[] = { - 0x00, - 0x06, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00 -}; -/** - * @} - */ - - -/** @defgroup MSC_DATA_Private_FunctionPrototypes - * @{ - */ -/** - * @} - */ - - -/** @defgroup MSC_DATA_Private_Functions - * @{ - */ - -/** - * @} - */ - - -/** - * @} - */ - - -/** - * @} - */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +/** + ****************************************************************************** + * @file usbd_msc_data.c + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief This file provides all the vital inquiry pages and sense data. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_msc_data.h" + + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup MSC_DATA + * @brief Mass storage info/data module + * @{ + */ + +/** @defgroup MSC_DATA_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_DATA_Private_Defines + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_DATA_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_DATA_Private_Variables + * @{ + */ + + +/* USB Mass storage Page 0 Inquiry Data */ +const uint8_t MSC_Page00_Inquiry_Data[] = {//7 + 0x00, + 0x00, + 0x00, + (LENGTH_INQUIRY_PAGE00 - 4), + 0x00, + 0x80, + 0x83 +}; +/* USB Mass storage sense 6 Data */ +const uint8_t MSC_Mode_Sense6_data[] = { + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 +}; +/* USB Mass storage sense 10 Data */ +const uint8_t MSC_Mode_Sense10_data[] = { + 0x00, + 0x06, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 +}; +/** + * @} + */ + + +/** @defgroup MSC_DATA_Private_FunctionPrototypes + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_DATA_Private_Functions + * @{ + */ + +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/usbdev/class/src/usbd_msc_scsi.c b/ports/stm32/usbdev/class/src/usbd_msc_scsi.c index b5363e2d4b..9da9033771 100644 --- a/ports/stm32/usbdev/class/src/usbd_msc_scsi.c +++ b/ports/stm32/usbdev/class/src/usbd_msc_scsi.c @@ -1,811 +1,811 @@ -/** - ****************************************************************************** - * @file usbd_msc_scsi.c - * @author MCD Application Team - * @version V2.0.0 - * @date 18-February-2014 - * @brief This file provides all the USBD SCSI layer functions. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT 2014 STMicroelectronics

- * - * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.st.com/software_license_agreement_liberty_v2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ****************************************************************************** - */ - -/* Includes ------------------------------------------------------------------*/ -#include "usbd_msc_bot.h" -#include "usbd_msc_scsi.h" -#include "usbd_msc_data.h" -#include "usbd_cdc_msc_hid.h" - - - -/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY - * @{ - */ - - -/** @defgroup MSC_SCSI - * @brief Mass storage SCSI layer module - * @{ - */ - -/** @defgroup MSC_SCSI_Private_TypesDefinitions - * @{ - */ -/** - * @} - */ - - -/** @defgroup MSC_SCSI_Private_Defines - * @{ - */ - -/** - * @} - */ - - -/** @defgroup MSC_SCSI_Private_Macros - * @{ - */ -/** - * @} - */ - - -/** @defgroup MSC_SCSI_Private_Variables - * @{ - */ - -/** - * @} - */ - - -/** @defgroup MSC_SCSI_Private_FunctionPrototypes - * @{ - */ -static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); -static int8_t SCSI_Inquiry(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); -static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); -static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); -static int8_t SCSI_RequestSense (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); -static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); -static int8_t SCSI_AllowMediumRemoval(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); -static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); -static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); -static int8_t SCSI_SynchronizeCache(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); -static int8_t SCSI_Write10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params); -static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params); -static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); -static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef *pdev, - uint8_t lun , - uint32_t blk_offset , - uint16_t blk_nbr); -static int8_t SCSI_ProcessRead (USBD_HandleTypeDef *pdev, - uint8_t lun); - -static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef *pdev, - uint8_t lun); -/** - * @} - */ - - -/** @defgroup MSC_SCSI_Private_Functions - * @{ - */ - - -/** -* @brief SCSI_ProcessCmd -* Process SCSI commands -* @param pdev: device instance -* @param lun: Logical unit number -* @param params: Command parameters -* @retval status -*/ -int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev, - uint8_t lun, - uint8_t *params) -{ - /* - if (params[0] != SCSI_READ10 && params[0] != SCSI_WRITE10) { - printf("SCSI_ProcessCmd(lun=%d, params=%x, %x)\n", lun, params[0], params[1]); - } - */ - - switch (params[0]) - { - case SCSI_TEST_UNIT_READY: - return SCSI_TestUnitReady(pdev, lun, params); - - case SCSI_REQUEST_SENSE: - return SCSI_RequestSense (pdev, lun, params); - case SCSI_INQUIRY: - return SCSI_Inquiry(pdev, lun, params); - - case SCSI_START_STOP_UNIT: - return SCSI_StartStopUnit(pdev, lun, params); - - case SCSI_ALLOW_MEDIUM_REMOVAL: - return SCSI_AllowMediumRemoval(pdev, lun, params); - - case SCSI_MODE_SENSE6: - return SCSI_ModeSense6 (pdev, lun, params); - - case SCSI_MODE_SENSE10: - return SCSI_ModeSense10 (pdev, lun, params); - - case SCSI_SYNCHRONIZE_CACHE10: - case SCSI_SYNCHRONIZE_CACHE16: - return SCSI_SynchronizeCache(pdev, lun, params); - - case SCSI_READ_FORMAT_CAPACITIES: - return SCSI_ReadFormatCapacity(pdev, lun, params); - - case SCSI_READ_CAPACITY10: - return SCSI_ReadCapacity10(pdev, lun, params); - - case SCSI_READ10: - return SCSI_Read10(pdev, lun, params); - - case SCSI_WRITE10: - return SCSI_Write10(pdev, lun, params); - - case SCSI_VERIFY10: - return SCSI_Verify10(pdev, lun, params); - - default: - SCSI_SenseCode(pdev, - lun, - ILLEGAL_REQUEST, - INVALID_CDB); - return -1; - } -} - - -/** -* @brief SCSI_TestUnitReady -* Process SCSI Test Unit Ready Command -* @param lun: Logical unit number -* @param params: Command parameters -* @retval status -*/ -static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - /* case 9 : Hi > D0 */ - if (hmsc->cbw.dDataLength != 0) - { - SCSI_SenseCode(pdev, - hmsc->cbw.bLUN, - ILLEGAL_REQUEST, - INVALID_CDB); - return -1; - } - - if(hmsc->bdev_ops->IsReady(lun) !=0 ) - { - SCSI_SenseCode(pdev, - lun, - NOT_READY, - MEDIUM_NOT_PRESENT); - - hmsc->bot_state = USBD_BOT_NO_DATA; - return -1; - } - hmsc->bot_data_length = 0; - return 0; -} - -/** -* @brief SCSI_Inquiry -* Process Inquiry command -* @param lun: Logical unit number -* @param params: Command parameters -* @retval status -*/ -static int8_t SCSI_Inquiry(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) -{ - uint8_t* pPage; - uint16_t len; - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - if (params[1] & 0x01)/*Evpd is set*/ - { - pPage = (uint8_t *)MSC_Page00_Inquiry_Data; - len = LENGTH_INQUIRY_PAGE00; - } - else - { - - pPage = (uint8_t *)&hmsc->bdev_ops->pInquiry[lun * STANDARD_INQUIRY_DATA_LEN]; - len = pPage[4] + 5; - - if (params[4] <= len) - { - len = params[4]; - } - } - hmsc->bot_data_length = len; - - while (len) - { - len--; - hmsc->bot_data[len] = pPage[len]; - } - return 0; -} - -/** -* @brief SCSI_ReadCapacity10 -* Process Read Capacity 10 command -* @param lun: Logical unit number -* @param params: Command parameters -* @retval status -*/ -static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - if(hmsc->bdev_ops->GetCapacity(lun, &hmsc->scsi_blk_nbr, &hmsc->scsi_blk_size) != 0) - { - SCSI_SenseCode(pdev, - lun, - NOT_READY, - MEDIUM_NOT_PRESENT); - return -1; - } - else - { - - hmsc->bot_data[0] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 24); - hmsc->bot_data[1] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 16); - hmsc->bot_data[2] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 8); - hmsc->bot_data[3] = (uint8_t)(hmsc->scsi_blk_nbr - 1); - - hmsc->bot_data[4] = (uint8_t)(hmsc->scsi_blk_size >> 24); - hmsc->bot_data[5] = (uint8_t)(hmsc->scsi_blk_size >> 16); - hmsc->bot_data[6] = (uint8_t)(hmsc->scsi_blk_size >> 8); - hmsc->bot_data[7] = (uint8_t)(hmsc->scsi_blk_size); - - hmsc->bot_data_length = 8; - return 0; - } -} -/** -* @brief SCSI_ReadFormatCapacity -* Process Read Format Capacity command -* @param lun: Logical unit number -* @param params: Command parameters -* @retval status -*/ -static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - uint16_t blk_size; - uint32_t blk_nbr; - uint16_t i; - - for(i=0 ; i < 12 ; i++) - { - hmsc->bot_data[i] = 0; - } - - if(hmsc->bdev_ops->GetCapacity(lun, &blk_nbr, &blk_size) != 0) - { - SCSI_SenseCode(pdev, - lun, - NOT_READY, - MEDIUM_NOT_PRESENT); - return -1; - } - else - { - hmsc->bot_data[3] = 0x08; - hmsc->bot_data[4] = (uint8_t)((blk_nbr - 1) >> 24); - hmsc->bot_data[5] = (uint8_t)((blk_nbr - 1) >> 16); - hmsc->bot_data[6] = (uint8_t)((blk_nbr - 1) >> 8); - hmsc->bot_data[7] = (uint8_t)(blk_nbr - 1); - - hmsc->bot_data[8] = 0x02; - hmsc->bot_data[9] = (uint8_t)(blk_size >> 16); - hmsc->bot_data[10] = (uint8_t)(blk_size >> 8); - hmsc->bot_data[11] = (uint8_t)(blk_size); - - hmsc->bot_data_length = 12; - return 0; - } -} -/** -* @brief SCSI_ModeSense6 -* Process Mode Sense6 command -* @param lun: Logical unit number -* @param params: Command parameters -* @retval status -*/ -static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - uint16_t len = 8 ; - hmsc->bot_data_length = len; - - while (len) - { - len--; - hmsc->bot_data[len] = MSC_Mode_Sense6_data[len]; - } - return 0; -} - -/** -* @brief SCSI_ModeSense10 -* Process Mode Sense10 command -* @param lun: Logical unit number -* @param params: Command parameters -* @retval status -*/ -static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) -{ - uint16_t len = 8; - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - hmsc->bot_data_length = len; - - while (len) - { - len--; - hmsc->bot_data[len] = MSC_Mode_Sense10_data[len]; - } - return 0; -} - -static int8_t SCSI_SynchronizeCache(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) { - // nothing to synchronize, so just return "success" - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - hmsc->bot_data_length = 0; - return 0; -} - -/** -* @brief SCSI_RequestSense -* Process Request Sense command -* @param lun: Logical unit number -* @param params: Command parameters -* @retval status -*/ - -static int8_t SCSI_RequestSense (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) -{ - uint8_t i; - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - for(i=0 ; i < REQUEST_SENSE_DATA_LEN ; i++) - { - hmsc->bot_data[i] = 0; - } - - hmsc->bot_data[0] = 0x70; - hmsc->bot_data[7] = REQUEST_SENSE_DATA_LEN - 6; - - if((hmsc->scsi_sense_head != hmsc->scsi_sense_tail)) { - - hmsc->bot_data[2] = hmsc->scsi_sense[hmsc->scsi_sense_head].Skey; - hmsc->bot_data[12] = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASCQ; - hmsc->bot_data[13] = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASC; - hmsc->scsi_sense_head++; - - if (hmsc->scsi_sense_head == SENSE_LIST_DEEPTH) - { - hmsc->scsi_sense_head = 0; - } - } - hmsc->bot_data_length = REQUEST_SENSE_DATA_LEN; - - if (params[4] <= REQUEST_SENSE_DATA_LEN) - { - hmsc->bot_data_length = params[4]; - } - return 0; -} - -/** -* @brief SCSI_SenseCode -* Load the last error code in the error list -* @param lun: Logical unit number -* @param sKey: Sense Key -* @param ASC: Additional Sense Key -* @retval none - -*/ -void SCSI_SenseCode(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t sKey, uint8_t ASC) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - hmsc->scsi_sense[hmsc->scsi_sense_tail].Skey = sKey; - hmsc->scsi_sense[hmsc->scsi_sense_tail].w.ASC = ASC << 8; - hmsc->scsi_sense_tail++; - if (hmsc->scsi_sense_tail == SENSE_LIST_DEEPTH) - { - hmsc->scsi_sense_tail = 0; - } -} -/** -* @brief SCSI_StartStopUnit -* Process Start Stop Unit command -* @param lun: Logical unit number -* @param params: Command parameters -* @retval status -*/ -static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - hmsc->bot_data_length = 0; - - // On Mac OS X, when the device is ejected a SCSI_START_STOP_UNIT command is sent. - // Bit 0 of params[4] is the START bit. - // If we get a stop, we must really stop the device so that the Mac does not - // automatically remount it. - hmsc->bdev_ops->StartStopUnit(lun, params[4] & 1); - - return 0; -} - -/** -* @brief SCSI_AllowMediumRemoval -* Process Allow Medium Removal command -* @param lun: Logical unit number -* @param params: Command parameters -* @retval status -*/ -static int8_t SCSI_AllowMediumRemoval(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - hmsc->bot_data_length = 0; - hmsc->bdev_ops->PreventAllowMediumRemoval(lun, params[4]); - return 0; -} - -/** -* @brief SCSI_Read10 -* Process Read10 command -* @param lun: Logical unit number -* @param params: Command parameters -* @retval status -*/ -static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - if(hmsc->bot_state == USBD_BOT_IDLE) /* Idle */ - { - - /* case 10 : Ho <> Di */ - - if ((hmsc->cbw.bmFlags & 0x80) != 0x80) - { - SCSI_SenseCode(pdev, - hmsc->cbw.bLUN, - ILLEGAL_REQUEST, - INVALID_CDB); - return -1; - } - - if(hmsc->bdev_ops->IsReady(lun) !=0 ) - { - SCSI_SenseCode(pdev, - lun, - NOT_READY, - MEDIUM_NOT_PRESENT); - return -1; - } - - hmsc->scsi_blk_addr_in_blks = (params[2] << 24) | \ - (params[3] << 16) | \ - (params[4] << 8) | \ - params[5]; - - hmsc->scsi_blk_len = (params[7] << 8) | \ - params[8]; - - - - if( SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr_in_blks, hmsc->scsi_blk_len) < 0) - { - return -1; /* error */ - } - - hmsc->bot_state = USBD_BOT_DATA_IN; - hmsc->scsi_blk_len *= hmsc->scsi_blk_size; - - /* cases 4,5 : Hi <> Dn */ - if (hmsc->cbw.dDataLength != hmsc->scsi_blk_len) - { - SCSI_SenseCode(pdev, - hmsc->cbw.bLUN, - ILLEGAL_REQUEST, - INVALID_CDB); - return -1; - } - } - hmsc->bot_data_length = MSC_MEDIA_PACKET; - - return SCSI_ProcessRead(pdev, lun); -} - -/** -* @brief SCSI_Write10 -* Process Write10 command -* @param lun: Logical unit number -* @param params: Command parameters -* @retval status -*/ - -static int8_t SCSI_Write10 (USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - if (hmsc->bot_state == USBD_BOT_IDLE) /* Idle */ - { - - /* case 8 : Hi <> Do */ - - if ((hmsc->cbw.bmFlags & 0x80) == 0x80) - { - SCSI_SenseCode(pdev, - hmsc->cbw.bLUN, - ILLEGAL_REQUEST, - INVALID_CDB); - return -1; - } - - /* Check whether Media is ready */ - if(hmsc->bdev_ops->IsReady(lun) !=0 ) - { - SCSI_SenseCode(pdev, - lun, - NOT_READY, - MEDIUM_NOT_PRESENT); - return -1; - } - - /* Check If media is write-protected */ - if(hmsc->bdev_ops->IsWriteProtected(lun) !=0 ) - { - SCSI_SenseCode(pdev, - lun, - NOT_READY, - WRITE_PROTECTED); - return -1; - } - - - hmsc->scsi_blk_addr_in_blks = (params[2] << 24) | \ - (params[3] << 16) | \ - (params[4] << 8) | \ - params[5]; - hmsc->scsi_blk_len = (params[7] << 8) | \ - params[8]; - - /* check if LBA address is in the right range */ - if(SCSI_CheckAddressRange(pdev, - lun, - hmsc->scsi_blk_addr_in_blks, - hmsc->scsi_blk_len) < 0) - { - return -1; /* error */ - } - - hmsc->scsi_blk_len *= hmsc->scsi_blk_size; - - /* cases 3,11,13 : Hn,Ho <> D0 */ - if (hmsc->cbw.dDataLength != hmsc->scsi_blk_len) - { - SCSI_SenseCode(pdev, - hmsc->cbw.bLUN, - ILLEGAL_REQUEST, - INVALID_CDB); - return -1; - } - - /* Prepare EP to receive first data packet */ - hmsc->bot_state = USBD_BOT_DATA_OUT; - USBD_LL_PrepareReceive (pdev, - MSC_OUT_EP, - hmsc->bot_data, - MIN (hmsc->scsi_blk_len, MSC_MEDIA_PACKET)); - } - else /* Write Process ongoing */ - { - return SCSI_ProcessWrite(pdev, lun); - } - return 0; -} - - -/** -* @brief SCSI_Verify10 -* Process Verify10 command -* @param lun: Logical unit number -* @param params: Command parameters -* @retval status -*/ - -static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - if ((params[1]& 0x02) == 0x02) - { - SCSI_SenseCode (pdev, - lun, - ILLEGAL_REQUEST, - INVALID_FIELED_IN_COMMAND); - return -1; /* Error, Verify Mode Not supported*/ - } - - hmsc->scsi_blk_addr_in_blks = (params[2] << 24) | (params[3] << 16) | (params[4] << 8) | params[5]; - hmsc->scsi_blk_len = (params[7] << 8) | params[8]; - - if(SCSI_CheckAddressRange(pdev, - lun, - hmsc->scsi_blk_addr_in_blks, - hmsc->scsi_blk_len) < 0) - { - return -1; /* error */ - } - hmsc->bot_data_length = 0; - return 0; -} - -/** -* @brief SCSI_CheckAddressRange -* Check address range -* @param lun: Logical unit number -* @param blk_offset: first block address -* @param blk_nbr: number of block to be processed -* @retval status -*/ -static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef *pdev, uint8_t lun , uint32_t blk_offset , uint16_t blk_nbr) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - if ((blk_offset + blk_nbr) > hmsc->scsi_blk_nbr ) - { - SCSI_SenseCode(pdev, - lun, - ILLEGAL_REQUEST, - ADDRESS_OUT_OF_RANGE); - return -1; - } - return 0; -} - -/** -* @brief SCSI_ProcessRead -* Handle Read Process -* @param lun: Logical unit number -* @retval status -*/ -static int8_t SCSI_ProcessRead (USBD_HandleTypeDef *pdev, uint8_t lun) -{ - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - uint32_t len; - - len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET); - - if( hmsc->bdev_ops->Read(lun , - hmsc->bot_data, - hmsc->scsi_blk_addr_in_blks, - len / hmsc->scsi_blk_size) < 0) - { - - SCSI_SenseCode(pdev, - lun, - HARDWARE_ERROR, - UNRECOVERED_READ_ERROR); - return -1; - } - - - USBD_LL_Transmit (pdev, - MSC_IN_EP, - hmsc->bot_data, - len); - - - hmsc->scsi_blk_addr_in_blks += len / hmsc->scsi_blk_size; - hmsc->scsi_blk_len -= len; - - /* case 6 : Hi = Di */ - hmsc->csw.dDataResidue -= len; - - if (hmsc->scsi_blk_len == 0) - { - hmsc->bot_state = USBD_BOT_LAST_DATA_IN; - } - return 0; -} - -/** -* @brief SCSI_ProcessWrite -* Handle Write Process -* @param lun: Logical unit number -* @retval status -*/ - -static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef *pdev, uint8_t lun) -{ - uint32_t len; - USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; - - len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET); - - if(hmsc->bdev_ops->Write(lun , - hmsc->bot_data, - hmsc->scsi_blk_addr_in_blks, - len / hmsc->scsi_blk_size) < 0) - { - SCSI_SenseCode(pdev, - lun, - HARDWARE_ERROR, - WRITE_FAULT); - return -1; - } - - - hmsc->scsi_blk_addr_in_blks += len / hmsc->scsi_blk_size; - hmsc->scsi_blk_len -= len; - - /* case 12 : Ho = Do */ - hmsc->csw.dDataResidue -= len; - - if (hmsc->scsi_blk_len == 0) - { - MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_PASSED); - } - else - { - /* Prapare EP to Receive next packet */ - USBD_LL_PrepareReceive (pdev, - MSC_OUT_EP, - hmsc->bot_data, - MIN (hmsc->scsi_blk_len, MSC_MEDIA_PACKET)); - } - - return 0; -} -/** - * @} - */ - - -/** - * @} - */ - - -/** - * @} - */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +/** + ****************************************************************************** + * @file usbd_msc_scsi.c + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief This file provides all the USBD SCSI layer functions. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_msc_bot.h" +#include "usbd_msc_scsi.h" +#include "usbd_msc_data.h" +#include "usbd_cdc_msc_hid.h" + + + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup MSC_SCSI + * @brief Mass storage SCSI layer module + * @{ + */ + +/** @defgroup MSC_SCSI_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_SCSI_Private_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup MSC_SCSI_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_SCSI_Private_Variables + * @{ + */ + +/** + * @} + */ + + +/** @defgroup MSC_SCSI_Private_FunctionPrototypes + * @{ + */ +static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_Inquiry(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_RequestSense (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_AllowMediumRemoval(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_SynchronizeCache(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_Write10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params); +static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params); +static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef *pdev, + uint8_t lun , + uint32_t blk_offset , + uint16_t blk_nbr); +static int8_t SCSI_ProcessRead (USBD_HandleTypeDef *pdev, + uint8_t lun); + +static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef *pdev, + uint8_t lun); +/** + * @} + */ + + +/** @defgroup MSC_SCSI_Private_Functions + * @{ + */ + + +/** +* @brief SCSI_ProcessCmd +* Process SCSI commands +* @param pdev: device instance +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev, + uint8_t lun, + uint8_t *params) +{ + /* + if (params[0] != SCSI_READ10 && params[0] != SCSI_WRITE10) { + printf("SCSI_ProcessCmd(lun=%d, params=%x, %x)\n", lun, params[0], params[1]); + } + */ + + switch (params[0]) + { + case SCSI_TEST_UNIT_READY: + return SCSI_TestUnitReady(pdev, lun, params); + + case SCSI_REQUEST_SENSE: + return SCSI_RequestSense (pdev, lun, params); + case SCSI_INQUIRY: + return SCSI_Inquiry(pdev, lun, params); + + case SCSI_START_STOP_UNIT: + return SCSI_StartStopUnit(pdev, lun, params); + + case SCSI_ALLOW_MEDIUM_REMOVAL: + return SCSI_AllowMediumRemoval(pdev, lun, params); + + case SCSI_MODE_SENSE6: + return SCSI_ModeSense6 (pdev, lun, params); + + case SCSI_MODE_SENSE10: + return SCSI_ModeSense10 (pdev, lun, params); + + case SCSI_SYNCHRONIZE_CACHE10: + case SCSI_SYNCHRONIZE_CACHE16: + return SCSI_SynchronizeCache(pdev, lun, params); + + case SCSI_READ_FORMAT_CAPACITIES: + return SCSI_ReadFormatCapacity(pdev, lun, params); + + case SCSI_READ_CAPACITY10: + return SCSI_ReadCapacity10(pdev, lun, params); + + case SCSI_READ10: + return SCSI_Read10(pdev, lun, params); + + case SCSI_WRITE10: + return SCSI_Write10(pdev, lun, params); + + case SCSI_VERIFY10: + return SCSI_Verify10(pdev, lun, params); + + default: + SCSI_SenseCode(pdev, + lun, + ILLEGAL_REQUEST, + INVALID_CDB); + return -1; + } +} + + +/** +* @brief SCSI_TestUnitReady +* Process SCSI Test Unit Ready Command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + /* case 9 : Hi > D0 */ + if (hmsc->cbw.dDataLength != 0) + { + SCSI_SenseCode(pdev, + hmsc->cbw.bLUN, + ILLEGAL_REQUEST, + INVALID_CDB); + return -1; + } + + if(hmsc->bdev_ops->IsReady(lun) !=0 ) + { + SCSI_SenseCode(pdev, + lun, + NOT_READY, + MEDIUM_NOT_PRESENT); + + hmsc->bot_state = USBD_BOT_NO_DATA; + return -1; + } + hmsc->bot_data_length = 0; + return 0; +} + +/** +* @brief SCSI_Inquiry +* Process Inquiry command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +static int8_t SCSI_Inquiry(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + uint8_t* pPage; + uint16_t len; + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + if (params[1] & 0x01)/*Evpd is set*/ + { + pPage = (uint8_t *)MSC_Page00_Inquiry_Data; + len = LENGTH_INQUIRY_PAGE00; + } + else + { + + pPage = (uint8_t *)&hmsc->bdev_ops->pInquiry[lun * STANDARD_INQUIRY_DATA_LEN]; + len = pPage[4] + 5; + + if (params[4] <= len) + { + len = params[4]; + } + } + hmsc->bot_data_length = len; + + while (len) + { + len--; + hmsc->bot_data[len] = pPage[len]; + } + return 0; +} + +/** +* @brief SCSI_ReadCapacity10 +* Process Read Capacity 10 command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + if(hmsc->bdev_ops->GetCapacity(lun, &hmsc->scsi_blk_nbr, &hmsc->scsi_blk_size) != 0) + { + SCSI_SenseCode(pdev, + lun, + NOT_READY, + MEDIUM_NOT_PRESENT); + return -1; + } + else + { + + hmsc->bot_data[0] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 24); + hmsc->bot_data[1] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 16); + hmsc->bot_data[2] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 8); + hmsc->bot_data[3] = (uint8_t)(hmsc->scsi_blk_nbr - 1); + + hmsc->bot_data[4] = (uint8_t)(hmsc->scsi_blk_size >> 24); + hmsc->bot_data[5] = (uint8_t)(hmsc->scsi_blk_size >> 16); + hmsc->bot_data[6] = (uint8_t)(hmsc->scsi_blk_size >> 8); + hmsc->bot_data[7] = (uint8_t)(hmsc->scsi_blk_size); + + hmsc->bot_data_length = 8; + return 0; + } +} +/** +* @brief SCSI_ReadFormatCapacity +* Process Read Format Capacity command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + uint16_t blk_size; + uint32_t blk_nbr; + uint16_t i; + + for(i=0 ; i < 12 ; i++) + { + hmsc->bot_data[i] = 0; + } + + if(hmsc->bdev_ops->GetCapacity(lun, &blk_nbr, &blk_size) != 0) + { + SCSI_SenseCode(pdev, + lun, + NOT_READY, + MEDIUM_NOT_PRESENT); + return -1; + } + else + { + hmsc->bot_data[3] = 0x08; + hmsc->bot_data[4] = (uint8_t)((blk_nbr - 1) >> 24); + hmsc->bot_data[5] = (uint8_t)((blk_nbr - 1) >> 16); + hmsc->bot_data[6] = (uint8_t)((blk_nbr - 1) >> 8); + hmsc->bot_data[7] = (uint8_t)(blk_nbr - 1); + + hmsc->bot_data[8] = 0x02; + hmsc->bot_data[9] = (uint8_t)(blk_size >> 16); + hmsc->bot_data[10] = (uint8_t)(blk_size >> 8); + hmsc->bot_data[11] = (uint8_t)(blk_size); + + hmsc->bot_data_length = 12; + return 0; + } +} +/** +* @brief SCSI_ModeSense6 +* Process Mode Sense6 command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + uint16_t len = 8 ; + hmsc->bot_data_length = len; + + while (len) + { + len--; + hmsc->bot_data[len] = MSC_Mode_Sense6_data[len]; + } + return 0; +} + +/** +* @brief SCSI_ModeSense10 +* Process Mode Sense10 command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + uint16_t len = 8; + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + hmsc->bot_data_length = len; + + while (len) + { + len--; + hmsc->bot_data[len] = MSC_Mode_Sense10_data[len]; + } + return 0; +} + +static int8_t SCSI_SynchronizeCache(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) { + // nothing to synchronize, so just return "success" + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + hmsc->bot_data_length = 0; + return 0; +} + +/** +* @brief SCSI_RequestSense +* Process Request Sense command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ + +static int8_t SCSI_RequestSense (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + uint8_t i; + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + for(i=0 ; i < REQUEST_SENSE_DATA_LEN ; i++) + { + hmsc->bot_data[i] = 0; + } + + hmsc->bot_data[0] = 0x70; + hmsc->bot_data[7] = REQUEST_SENSE_DATA_LEN - 6; + + if((hmsc->scsi_sense_head != hmsc->scsi_sense_tail)) { + + hmsc->bot_data[2] = hmsc->scsi_sense[hmsc->scsi_sense_head].Skey; + hmsc->bot_data[12] = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASCQ; + hmsc->bot_data[13] = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASC; + hmsc->scsi_sense_head++; + + if (hmsc->scsi_sense_head == SENSE_LIST_DEEPTH) + { + hmsc->scsi_sense_head = 0; + } + } + hmsc->bot_data_length = REQUEST_SENSE_DATA_LEN; + + if (params[4] <= REQUEST_SENSE_DATA_LEN) + { + hmsc->bot_data_length = params[4]; + } + return 0; +} + +/** +* @brief SCSI_SenseCode +* Load the last error code in the error list +* @param lun: Logical unit number +* @param sKey: Sense Key +* @param ASC: Additional Sense Key +* @retval none + +*/ +void SCSI_SenseCode(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t sKey, uint8_t ASC) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + hmsc->scsi_sense[hmsc->scsi_sense_tail].Skey = sKey; + hmsc->scsi_sense[hmsc->scsi_sense_tail].w.ASC = ASC << 8; + hmsc->scsi_sense_tail++; + if (hmsc->scsi_sense_tail == SENSE_LIST_DEEPTH) + { + hmsc->scsi_sense_tail = 0; + } +} +/** +* @brief SCSI_StartStopUnit +* Process Start Stop Unit command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + hmsc->bot_data_length = 0; + + // On Mac OS X, when the device is ejected a SCSI_START_STOP_UNIT command is sent. + // Bit 0 of params[4] is the START bit. + // If we get a stop, we must really stop the device so that the Mac does not + // automatically remount it. + hmsc->bdev_ops->StartStopUnit(lun, params[4] & 1); + + return 0; +} + +/** +* @brief SCSI_AllowMediumRemoval +* Process Allow Medium Removal command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +static int8_t SCSI_AllowMediumRemoval(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + hmsc->bot_data_length = 0; + hmsc->bdev_ops->PreventAllowMediumRemoval(lun, params[4]); + return 0; +} + +/** +* @brief SCSI_Read10 +* Process Read10 command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + if(hmsc->bot_state == USBD_BOT_IDLE) /* Idle */ + { + + /* case 10 : Ho <> Di */ + + if ((hmsc->cbw.bmFlags & 0x80) != 0x80) + { + SCSI_SenseCode(pdev, + hmsc->cbw.bLUN, + ILLEGAL_REQUEST, + INVALID_CDB); + return -1; + } + + if(hmsc->bdev_ops->IsReady(lun) !=0 ) + { + SCSI_SenseCode(pdev, + lun, + NOT_READY, + MEDIUM_NOT_PRESENT); + return -1; + } + + hmsc->scsi_blk_addr_in_blks = (params[2] << 24) | \ + (params[3] << 16) | \ + (params[4] << 8) | \ + params[5]; + + hmsc->scsi_blk_len = (params[7] << 8) | \ + params[8]; + + + + if( SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr_in_blks, hmsc->scsi_blk_len) < 0) + { + return -1; /* error */ + } + + hmsc->bot_state = USBD_BOT_DATA_IN; + hmsc->scsi_blk_len *= hmsc->scsi_blk_size; + + /* cases 4,5 : Hi <> Dn */ + if (hmsc->cbw.dDataLength != hmsc->scsi_blk_len) + { + SCSI_SenseCode(pdev, + hmsc->cbw.bLUN, + ILLEGAL_REQUEST, + INVALID_CDB); + return -1; + } + } + hmsc->bot_data_length = MSC_MEDIA_PACKET; + + return SCSI_ProcessRead(pdev, lun); +} + +/** +* @brief SCSI_Write10 +* Process Write10 command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ + +static int8_t SCSI_Write10 (USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + if (hmsc->bot_state == USBD_BOT_IDLE) /* Idle */ + { + + /* case 8 : Hi <> Do */ + + if ((hmsc->cbw.bmFlags & 0x80) == 0x80) + { + SCSI_SenseCode(pdev, + hmsc->cbw.bLUN, + ILLEGAL_REQUEST, + INVALID_CDB); + return -1; + } + + /* Check whether Media is ready */ + if(hmsc->bdev_ops->IsReady(lun) !=0 ) + { + SCSI_SenseCode(pdev, + lun, + NOT_READY, + MEDIUM_NOT_PRESENT); + return -1; + } + + /* Check If media is write-protected */ + if(hmsc->bdev_ops->IsWriteProtected(lun) !=0 ) + { + SCSI_SenseCode(pdev, + lun, + NOT_READY, + WRITE_PROTECTED); + return -1; + } + + + hmsc->scsi_blk_addr_in_blks = (params[2] << 24) | \ + (params[3] << 16) | \ + (params[4] << 8) | \ + params[5]; + hmsc->scsi_blk_len = (params[7] << 8) | \ + params[8]; + + /* check if LBA address is in the right range */ + if(SCSI_CheckAddressRange(pdev, + lun, + hmsc->scsi_blk_addr_in_blks, + hmsc->scsi_blk_len) < 0) + { + return -1; /* error */ + } + + hmsc->scsi_blk_len *= hmsc->scsi_blk_size; + + /* cases 3,11,13 : Hn,Ho <> D0 */ + if (hmsc->cbw.dDataLength != hmsc->scsi_blk_len) + { + SCSI_SenseCode(pdev, + hmsc->cbw.bLUN, + ILLEGAL_REQUEST, + INVALID_CDB); + return -1; + } + + /* Prepare EP to receive first data packet */ + hmsc->bot_state = USBD_BOT_DATA_OUT; + USBD_LL_PrepareReceive (pdev, + MSC_OUT_EP, + hmsc->bot_data, + MIN (hmsc->scsi_blk_len, MSC_MEDIA_PACKET)); + } + else /* Write Process ongoing */ + { + return SCSI_ProcessWrite(pdev, lun); + } + return 0; +} + + +/** +* @brief SCSI_Verify10 +* Process Verify10 command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ + +static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + if ((params[1]& 0x02) == 0x02) + { + SCSI_SenseCode (pdev, + lun, + ILLEGAL_REQUEST, + INVALID_FIELED_IN_COMMAND); + return -1; /* Error, Verify Mode Not supported*/ + } + + hmsc->scsi_blk_addr_in_blks = (params[2] << 24) | (params[3] << 16) | (params[4] << 8) | params[5]; + hmsc->scsi_blk_len = (params[7] << 8) | params[8]; + + if(SCSI_CheckAddressRange(pdev, + lun, + hmsc->scsi_blk_addr_in_blks, + hmsc->scsi_blk_len) < 0) + { + return -1; /* error */ + } + hmsc->bot_data_length = 0; + return 0; +} + +/** +* @brief SCSI_CheckAddressRange +* Check address range +* @param lun: Logical unit number +* @param blk_offset: first block address +* @param blk_nbr: number of block to be processed +* @retval status +*/ +static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef *pdev, uint8_t lun , uint32_t blk_offset , uint16_t blk_nbr) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + if ((blk_offset + blk_nbr) > hmsc->scsi_blk_nbr ) + { + SCSI_SenseCode(pdev, + lun, + ILLEGAL_REQUEST, + ADDRESS_OUT_OF_RANGE); + return -1; + } + return 0; +} + +/** +* @brief SCSI_ProcessRead +* Handle Read Process +* @param lun: Logical unit number +* @retval status +*/ +static int8_t SCSI_ProcessRead (USBD_HandleTypeDef *pdev, uint8_t lun) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + uint32_t len; + + len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET); + + if( hmsc->bdev_ops->Read(lun , + hmsc->bot_data, + hmsc->scsi_blk_addr_in_blks, + len / hmsc->scsi_blk_size) < 0) + { + + SCSI_SenseCode(pdev, + lun, + HARDWARE_ERROR, + UNRECOVERED_READ_ERROR); + return -1; + } + + + USBD_LL_Transmit (pdev, + MSC_IN_EP, + hmsc->bot_data, + len); + + + hmsc->scsi_blk_addr_in_blks += len / hmsc->scsi_blk_size; + hmsc->scsi_blk_len -= len; + + /* case 6 : Hi = Di */ + hmsc->csw.dDataResidue -= len; + + if (hmsc->scsi_blk_len == 0) + { + hmsc->bot_state = USBD_BOT_LAST_DATA_IN; + } + return 0; +} + +/** +* @brief SCSI_ProcessWrite +* Handle Write Process +* @param lun: Logical unit number +* @retval status +*/ + +static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef *pdev, uint8_t lun) +{ + uint32_t len; + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET); + + if(hmsc->bdev_ops->Write(lun , + hmsc->bot_data, + hmsc->scsi_blk_addr_in_blks, + len / hmsc->scsi_blk_size) < 0) + { + SCSI_SenseCode(pdev, + lun, + HARDWARE_ERROR, + WRITE_FAULT); + return -1; + } + + + hmsc->scsi_blk_addr_in_blks += len / hmsc->scsi_blk_size; + hmsc->scsi_blk_len -= len; + + /* case 12 : Ho = Do */ + hmsc->csw.dDataResidue -= len; + + if (hmsc->scsi_blk_len == 0) + { + MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_PASSED); + } + else + { + /* Prapare EP to Receive next packet */ + USBD_LL_PrepareReceive (pdev, + MSC_OUT_EP, + hmsc->bot_data, + MIN (hmsc->scsi_blk_len, MSC_MEDIA_PACKET)); + } + + return 0; +} +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/usbdev/core/inc/usbd_core.h b/ports/stm32/usbdev/core/inc/usbd_core.h index fb1d541f6b..5494be3a22 100644 --- a/ports/stm32/usbdev/core/inc/usbd_core.h +++ b/ports/stm32/usbdev/core/inc/usbd_core.h @@ -1,159 +1,159 @@ -/** - ****************************************************************************** - * @file usbd_core.h - * @author MCD Application Team - * @version V2.0.0 - * @date 18-February-2014 - * @brief Header file for usbd_core.c - ****************************************************************************** - * @attention - * - *

© COPYRIGHT 2014 STMicroelectronics

- * - * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.st.com/software_license_agreement_liberty_v2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USBD_CORE_H -#define __USBD_CORE_H - -/* Includes ------------------------------------------------------------------*/ -#include "usbd_conf.h" -#include "usbd_def.h" -#include "usbd_ioreq.h" -#include "usbd_ctlreq.h" - -/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY - * @{ - */ - -/** @defgroup USBD_CORE - * @brief This file is the Header file for usbd_core.c file - * @{ - */ - - -/** @defgroup USBD_CORE_Exported_Defines - * @{ - */ - -/** - * @} - */ - - -/** @defgroup USBD_CORE_Exported_TypesDefinitions - * @{ - */ - - -/** - * @} - */ - - - -/** @defgroup USBD_CORE_Exported_Macros - * @{ - */ - -/** - * @} - */ - -/** @defgroup USBD_CORE_Exported_Variables - * @{ - */ -#define USBD_SOF USBD_LL_SOF -/** - * @} - */ - -/** @defgroup USBD_CORE_Exported_FunctionsPrototype - * @{ - */ -USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev, USBD_DescriptorsTypeDef *pdesc, uint8_t id); -USBD_StatusTypeDef USBD_DeInit(USBD_HandleTypeDef *pdev); -USBD_StatusTypeDef USBD_Start (USBD_HandleTypeDef *pdev); -USBD_StatusTypeDef USBD_Stop (USBD_HandleTypeDef *pdev); -USBD_StatusTypeDef USBD_RegisterClass(USBD_HandleTypeDef *pdev, const USBD_ClassTypeDef *pclass); - -USBD_StatusTypeDef USBD_RunTestMode (USBD_HandleTypeDef *pdev); -USBD_StatusTypeDef USBD_SetClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx); -USBD_StatusTypeDef USBD_ClrClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx); - -USBD_StatusTypeDef USBD_LL_SetupStage(USBD_HandleTypeDef *pdev, uint8_t *psetup); -USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata); -USBD_StatusTypeDef USBD_LL_DataInStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata); - -USBD_StatusTypeDef USBD_LL_Reset(USBD_HandleTypeDef *pdev); -USBD_StatusTypeDef USBD_LL_SetSpeed(USBD_HandleTypeDef *pdev, USBD_SpeedTypeDef speed); -USBD_StatusTypeDef USBD_LL_Suspend(USBD_HandleTypeDef *pdev); -USBD_StatusTypeDef USBD_LL_Resume(USBD_HandleTypeDef *pdev); - -USBD_StatusTypeDef USBD_LL_SOF(USBD_HandleTypeDef *pdev); -USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum); -USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum); - -USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev); -USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev); - -/* USBD Low Level Driver */ -USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev, int high_speed); -USBD_StatusTypeDef USBD_LL_DeInit (USBD_HandleTypeDef *pdev); -USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev); -USBD_StatusTypeDef USBD_LL_Stop (USBD_HandleTypeDef *pdev); -USBD_StatusTypeDef USBD_LL_OpenEP (USBD_HandleTypeDef *pdev, - uint8_t ep_addr, - uint8_t ep_type, - uint16_t ep_mps); - -USBD_StatusTypeDef USBD_LL_CloseEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr); -USBD_StatusTypeDef USBD_LL_FlushEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr); -USBD_StatusTypeDef USBD_LL_StallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr); -USBD_StatusTypeDef USBD_LL_ClearStallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr); -uint8_t USBD_LL_IsStallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr); -USBD_StatusTypeDef USBD_LL_SetUSBAddress (USBD_HandleTypeDef *pdev, uint8_t dev_addr); -USBD_StatusTypeDef USBD_LL_Transmit (USBD_HandleTypeDef *pdev, - uint8_t ep_addr, - uint8_t *pbuf, - uint16_t size); - -USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, - uint8_t ep_addr, - uint8_t *pbuf, - uint16_t size); - -uint32_t USBD_LL_GetRxDataSize (USBD_HandleTypeDef *pdev, uint8_t ep_addr); -void USBD_LL_Delay (uint32_t Delay); - -/** - * @} - */ - -#endif /* __USBD_CORE_H */ - -/** - * @} - */ - -/** -* @} -*/ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ - - - +/** + ****************************************************************************** + * @file usbd_core.h + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief Header file for usbd_core.c + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_CORE_H +#define __USBD_CORE_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_conf.h" +#include "usbd_def.h" +#include "usbd_ioreq.h" +#include "usbd_ctlreq.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USBD_CORE + * @brief This file is the Header file for usbd_core.c file + * @{ + */ + + +/** @defgroup USBD_CORE_Exported_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBD_CORE_Exported_TypesDefinitions + * @{ + */ + + +/** + * @} + */ + + + +/** @defgroup USBD_CORE_Exported_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_CORE_Exported_Variables + * @{ + */ +#define USBD_SOF USBD_LL_SOF +/** + * @} + */ + +/** @defgroup USBD_CORE_Exported_FunctionsPrototype + * @{ + */ +USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev, USBD_DescriptorsTypeDef *pdesc, uint8_t id); +USBD_StatusTypeDef USBD_DeInit(USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_Start (USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_Stop (USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_RegisterClass(USBD_HandleTypeDef *pdev, const USBD_ClassTypeDef *pclass); + +USBD_StatusTypeDef USBD_RunTestMode (USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_SetClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx); +USBD_StatusTypeDef USBD_ClrClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx); + +USBD_StatusTypeDef USBD_LL_SetupStage(USBD_HandleTypeDef *pdev, uint8_t *psetup); +USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata); +USBD_StatusTypeDef USBD_LL_DataInStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata); + +USBD_StatusTypeDef USBD_LL_Reset(USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_SetSpeed(USBD_HandleTypeDef *pdev, USBD_SpeedTypeDef speed); +USBD_StatusTypeDef USBD_LL_Suspend(USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_Resume(USBD_HandleTypeDef *pdev); + +USBD_StatusTypeDef USBD_LL_SOF(USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum); +USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum); + +USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev); + +/* USBD Low Level Driver */ +USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev, int high_speed); +USBD_StatusTypeDef USBD_LL_DeInit (USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_Stop (USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_OpenEP (USBD_HandleTypeDef *pdev, + uint8_t ep_addr, + uint8_t ep_type, + uint16_t ep_mps); + +USBD_StatusTypeDef USBD_LL_CloseEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr); +USBD_StatusTypeDef USBD_LL_FlushEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr); +USBD_StatusTypeDef USBD_LL_StallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr); +USBD_StatusTypeDef USBD_LL_ClearStallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr); +uint8_t USBD_LL_IsStallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr); +USBD_StatusTypeDef USBD_LL_SetUSBAddress (USBD_HandleTypeDef *pdev, uint8_t dev_addr); +USBD_StatusTypeDef USBD_LL_Transmit (USBD_HandleTypeDef *pdev, + uint8_t ep_addr, + uint8_t *pbuf, + uint16_t size); + +USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, + uint8_t ep_addr, + uint8_t *pbuf, + uint16_t size); + +uint32_t USBD_LL_GetRxDataSize (USBD_HandleTypeDef *pdev, uint8_t ep_addr); +void USBD_LL_Delay (uint32_t Delay); + +/** + * @} + */ + +#endif /* __USBD_CORE_H */ + +/** + * @} + */ + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + + + diff --git a/ports/stm32/usbdev/core/inc/usbd_ctlreq.h b/ports/stm32/usbdev/core/inc/usbd_ctlreq.h index 9edf079247..8c26884e64 100644 --- a/ports/stm32/usbdev/core/inc/usbd_ctlreq.h +++ b/ports/stm32/usbdev/core/inc/usbd_ctlreq.h @@ -1,106 +1,106 @@ -/** - ****************************************************************************** - * @file usbd_req.h - * @author MCD Application Team - * @version V2.0.0 - * @date 18-February-2014 - * @brief header file for the usbd_req.c file - ****************************************************************************** - * @attention - * - *

© COPYRIGHT 2014 STMicroelectronics

- * - * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.st.com/software_license_agreement_liberty_v2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ - -#ifndef __USB_REQUEST_H_ -#define __USB_REQUEST_H_ - -/* Includes ------------------------------------------------------------------*/ -#include "usbd_def.h" - - -/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY - * @{ - */ - -/** @defgroup USBD_REQ - * @brief header file for the usbd_ioreq.c file - * @{ - */ - -/** @defgroup USBD_REQ_Exported_Defines - * @{ - */ -/** - * @} - */ - - -/** @defgroup USBD_REQ_Exported_Types - * @{ - */ -/** - * @} - */ - - - -/** @defgroup USBD_REQ_Exported_Macros - * @{ - */ -/** - * @} - */ - -/** @defgroup USBD_REQ_Exported_Variables - * @{ - */ -/** - * @} - */ - -/** @defgroup USBD_REQ_Exported_FunctionsPrototype - * @{ - */ - -USBD_StatusTypeDef USBD_StdDevReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); -USBD_StatusTypeDef USBD_StdItfReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); -USBD_StatusTypeDef USBD_StdEPReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); - - -void USBD_CtlError (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); - -void USBD_ParseSetupRequest (USBD_SetupReqTypedef *req, uint8_t *pdata); - -void USBD_GetString (uint8_t *desc, uint8_t *unicode, uint16_t *len); -/** - * @} - */ - -#endif /* __USB_REQUEST_H_ */ - -/** - * @} - */ - -/** -* @} -*/ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +/** + ****************************************************************************** + * @file usbd_req.h + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief header file for the usbd_req.c file + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ + +#ifndef __USB_REQUEST_H_ +#define __USB_REQUEST_H_ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_def.h" + + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USBD_REQ + * @brief header file for the usbd_ioreq.c file + * @{ + */ + +/** @defgroup USBD_REQ_Exported_Defines + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_REQ_Exported_Types + * @{ + */ +/** + * @} + */ + + + +/** @defgroup USBD_REQ_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USBD_REQ_Exported_Variables + * @{ + */ +/** + * @} + */ + +/** @defgroup USBD_REQ_Exported_FunctionsPrototype + * @{ + */ + +USBD_StatusTypeDef USBD_StdDevReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); +USBD_StatusTypeDef USBD_StdItfReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); +USBD_StatusTypeDef USBD_StdEPReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); + + +void USBD_CtlError (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); + +void USBD_ParseSetupRequest (USBD_SetupReqTypedef *req, uint8_t *pdata); + +void USBD_GetString (uint8_t *desc, uint8_t *unicode, uint16_t *len); +/** + * @} + */ + +#endif /* __USB_REQUEST_H_ */ + +/** + * @} + */ + +/** +* @} +*/ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/usbdev/core/inc/usbd_def.h b/ports/stm32/usbdev/core/inc/usbd_def.h index 1402062964..e0d1c37625 100644 --- a/ports/stm32/usbdev/core/inc/usbd_def.h +++ b/ports/stm32/usbdev/core/inc/usbd_def.h @@ -1,313 +1,313 @@ -/** - ****************************************************************************** - * @file usbd_def.h - * @author MCD Application Team - * @version V2.0.0 - * @date 18-February-2014 - * @brief general defines for the usb device library - ****************************************************************************** - * @attention - * - *

© COPYRIGHT 2014 STMicroelectronics

- * - * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.st.com/software_license_agreement_liberty_v2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ - -#ifndef __USBD_DEF_H -#define __USBD_DEF_H - -/* Includes ------------------------------------------------------------------*/ -#include "usbd_conf.h" - -/** @addtogroup STM32_USBD_DEVICE_LIBRARY - * @{ - */ - -/** @defgroup USB_DEF - * @brief general defines for the usb device library file - * @{ - */ - -/** @defgroup USB_DEF_Exported_Defines - * @{ - */ - -#ifndef NULL -#define NULL ((void *)0) -#endif - - -#define USB_LEN_DEV_QUALIFIER_DESC 0x0A -#define USB_LEN_DEV_DESC 0x12 -#define USB_LEN_CFG_DESC 0x09 -#define USB_LEN_IF_DESC 0x09 -#define USB_LEN_EP_DESC 0x07 -#define USB_LEN_OTG_DESC 0x03 -#define USB_LEN_LANGID_STR_DESC 0x04 -#define USB_LEN_OTHER_SPEED_DESC_SIZ 0x09 - -#define USBD_IDX_LANGID_STR 0x00 -#define USBD_IDX_MFC_STR 0x01 -#define USBD_IDX_PRODUCT_STR 0x02 -#define USBD_IDX_SERIAL_STR 0x03 -#define USBD_IDX_CONFIG_STR 0x04 -#define USBD_IDX_INTERFACE_STR 0x05 - -#define USB_REQ_TYPE_STANDARD 0x00 -#define USB_REQ_TYPE_CLASS 0x20 -#define USB_REQ_TYPE_VENDOR 0x40 -#define USB_REQ_TYPE_MASK 0x60 - -#define USB_REQ_RECIPIENT_DEVICE 0x00 -#define USB_REQ_RECIPIENT_INTERFACE 0x01 -#define USB_REQ_RECIPIENT_ENDPOINT 0x02 -#define USB_REQ_RECIPIENT_MASK 0x03 - -#define USB_REQ_GET_STATUS 0x00 -#define USB_REQ_CLEAR_FEATURE 0x01 -#define USB_REQ_SET_FEATURE 0x03 -#define USB_REQ_SET_ADDRESS 0x05 -#define USB_REQ_GET_DESCRIPTOR 0x06 -#define USB_REQ_SET_DESCRIPTOR 0x07 -#define USB_REQ_GET_CONFIGURATION 0x08 -#define USB_REQ_SET_CONFIGURATION 0x09 -#define USB_REQ_GET_INTERFACE 0x0A -#define USB_REQ_SET_INTERFACE 0x0B -#define USB_REQ_SYNCH_FRAME 0x0C - -#define USB_DESC_TYPE_DEVICE 1 -#define USB_DESC_TYPE_CONFIGURATION 2 -#define USB_DESC_TYPE_STRING 3 -#define USB_DESC_TYPE_INTERFACE 4 -#define USB_DESC_TYPE_ENDPOINT 5 -#define USB_DESC_TYPE_DEVICE_QUALIFIER 6 -#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 7 - - -#define USB_CONFIG_REMOTE_WAKEUP 2 -#define USB_CONFIG_SELF_POWERED 1 - -#define USB_FEATURE_EP_HALT 0 -#define USB_FEATURE_REMOTE_WAKEUP 1 -#define USB_FEATURE_TEST_MODE 2 - - -#define USB_HS_MAX_PACKET_SIZE 512 -#define USB_FS_MAX_PACKET_SIZE 64 -#define USB_MAX_EP0_SIZE 64 - -/* Device Status */ -#define USBD_STATE_DEFAULT 1 -#define USBD_STATE_ADDRESSED 2 -#define USBD_STATE_CONFIGURED 3 -#define USBD_STATE_SUSPENDED 4 - - -/* EP0 State */ -#define USBD_EP0_IDLE 0 -#define USBD_EP0_SETUP 1 -#define USBD_EP0_DATA_IN 2 -#define USBD_EP0_DATA_OUT 3 -#define USBD_EP0_STATUS_IN 4 -#define USBD_EP0_STATUS_OUT 5 -#define USBD_EP0_STALL 6 - -#define USBD_EP_TYPE_CTRL 0 -#define USBD_EP_TYPE_ISOC 1 -#define USBD_EP_TYPE_BULK 2 -#define USBD_EP_TYPE_INTR 3 - - -/** - * @} - */ - - -/** @defgroup USBD_DEF_Exported_TypesDefinitions - * @{ - */ - -typedef struct usb_setup_req -{ - - uint8_t bmRequest; - uint8_t bRequest; - uint16_t wValue; - uint16_t wIndex; - uint16_t wLength; -}USBD_SetupReqTypedef; - -struct _USBD_HandleTypeDef; - -typedef struct _Device_cb -{ - uint8_t (*Init) (struct _USBD_HandleTypeDef *pdev , uint8_t cfgidx); - uint8_t (*DeInit) (struct _USBD_HandleTypeDef *pdev , uint8_t cfgidx); - /* Control Endpoints*/ - uint8_t (*Setup) (struct _USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req); - uint8_t (*EP0_TxSent) (struct _USBD_HandleTypeDef *pdev ); - uint8_t (*EP0_RxReady) (struct _USBD_HandleTypeDef *pdev ); - /* Class Specific Endpoints*/ - uint8_t (*DataIn) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); - uint8_t (*DataOut) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); - uint8_t (*SOF) (struct _USBD_HandleTypeDef *pdev); - uint8_t (*IsoINIncomplete) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); - uint8_t (*IsoOUTIncomplete) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); - - uint8_t *(*GetHSConfigDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); - uint8_t *(*GetFSConfigDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); - uint8_t *(*GetOtherSpeedConfigDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); - uint8_t *(*GetDeviceQualifierDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); - -} USBD_ClassTypeDef; - -/* Following USB Device Speed */ -typedef enum -{ - USBD_SPEED_HIGH = 0, - USBD_SPEED_FULL = 1, - USBD_SPEED_LOW = 2, -}USBD_SpeedTypeDef; - -/* Following USB Device status */ -typedef enum { - USBD_OK = 0, - USBD_BUSY, - USBD_FAIL, -}USBD_StatusTypeDef; - -struct _USBD_HandleTypeDef; - -/* USB Device descriptors structure */ -typedef struct -{ - uint8_t *(*GetDeviceDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); - uint8_t *(*GetStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint8_t idx, uint16_t *length); -} USBD_DescriptorsTypeDef; - -/* USB Device handle structure */ -typedef struct -{ - uint32_t status; - uint32_t total_length; - uint32_t rem_length; - uint32_t maxpacket; -} USBD_EndpointTypeDef; - -/* USB Device handle structure */ -typedef struct _USBD_HandleTypeDef -{ - uint8_t id; - uint32_t dev_config; - uint32_t dev_default_config; - uint32_t dev_config_status; - USBD_SpeedTypeDef dev_speed; - USBD_EndpointTypeDef ep_in[15]; - USBD_EndpointTypeDef ep_out[15]; - uint32_t ep0_state; - uint32_t ep0_data_len; - uint8_t dev_state; - uint8_t dev_old_state; - uint8_t dev_address; - uint8_t dev_connection_status; - uint8_t dev_test_mode; - uint32_t dev_remote_wakeup; - - USBD_SetupReqTypedef request; - USBD_DescriptorsTypeDef *pDesc; - const USBD_ClassTypeDef *pClass; - void *pClassData; - void *pUserData; - void *pData; -} USBD_HandleTypeDef; - -/** - * @} - */ - - - -/** @defgroup USBD_DEF_Exported_Macros - * @{ - */ -#define SWAPBYTE(addr) (((uint16_t)(*((uint8_t *)(addr)))) + \ - (((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8)) - -#define LOBYTE(x) ((uint8_t)(x & 0x00FF)) -#define HIBYTE(x) ((uint8_t)((x & 0xFF00) >>8)) -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) - - -#if defined ( __GNUC__ ) - #ifndef __weak - #define __weak __attribute__((weak)) - #endif /* __weak */ - #ifndef __packed - #define __packed __attribute__((__packed__)) - #endif /* __packed */ -#endif /* __GNUC__ */ - - -/* In HS mode and when the DMA is used, all variables and data structures dealing - with the DMA during the transaction process should be 4-bytes aligned */ - -#if defined (__GNUC__) /* GNU Compiler */ - #define __ALIGN_END __attribute__ ((aligned (4))) - #define __ALIGN_BEGIN -#else - #define __ALIGN_END - #if defined (__CC_ARM) /* ARM Compiler */ - #define __ALIGN_BEGIN __align(4) - #elif defined (__ICCARM__) /* IAR Compiler */ - #define __ALIGN_BEGIN - #elif defined (__TASKING__) /* TASKING Compiler */ - #define __ALIGN_BEGIN __align(4) - #endif /* __CC_ARM */ -#endif /* __GNUC__ */ - - -/** - * @} - */ - -/** @defgroup USBD_DEF_Exported_Variables - * @{ - */ - -/** - * @} - */ - -/** @defgroup USBD_DEF_Exported_FunctionsPrototype - * @{ - */ - -/** - * @} - */ - -#endif /* __USBD_DEF_H */ - -/** - * @} - */ - -/** -* @} -*/ -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +/** + ****************************************************************************** + * @file usbd_def.h + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief general defines for the usb device library + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ + +#ifndef __USBD_DEF_H +#define __USBD_DEF_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_conf.h" + +/** @addtogroup STM32_USBD_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USB_DEF + * @brief general defines for the usb device library file + * @{ + */ + +/** @defgroup USB_DEF_Exported_Defines + * @{ + */ + +#ifndef NULL +#define NULL ((void *)0) +#endif + + +#define USB_LEN_DEV_QUALIFIER_DESC 0x0A +#define USB_LEN_DEV_DESC 0x12 +#define USB_LEN_CFG_DESC 0x09 +#define USB_LEN_IF_DESC 0x09 +#define USB_LEN_EP_DESC 0x07 +#define USB_LEN_OTG_DESC 0x03 +#define USB_LEN_LANGID_STR_DESC 0x04 +#define USB_LEN_OTHER_SPEED_DESC_SIZ 0x09 + +#define USBD_IDX_LANGID_STR 0x00 +#define USBD_IDX_MFC_STR 0x01 +#define USBD_IDX_PRODUCT_STR 0x02 +#define USBD_IDX_SERIAL_STR 0x03 +#define USBD_IDX_CONFIG_STR 0x04 +#define USBD_IDX_INTERFACE_STR 0x05 + +#define USB_REQ_TYPE_STANDARD 0x00 +#define USB_REQ_TYPE_CLASS 0x20 +#define USB_REQ_TYPE_VENDOR 0x40 +#define USB_REQ_TYPE_MASK 0x60 + +#define USB_REQ_RECIPIENT_DEVICE 0x00 +#define USB_REQ_RECIPIENT_INTERFACE 0x01 +#define USB_REQ_RECIPIENT_ENDPOINT 0x02 +#define USB_REQ_RECIPIENT_MASK 0x03 + +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + +#define USB_DESC_TYPE_DEVICE 1 +#define USB_DESC_TYPE_CONFIGURATION 2 +#define USB_DESC_TYPE_STRING 3 +#define USB_DESC_TYPE_INTERFACE 4 +#define USB_DESC_TYPE_ENDPOINT 5 +#define USB_DESC_TYPE_DEVICE_QUALIFIER 6 +#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 7 + + +#define USB_CONFIG_REMOTE_WAKEUP 2 +#define USB_CONFIG_SELF_POWERED 1 + +#define USB_FEATURE_EP_HALT 0 +#define USB_FEATURE_REMOTE_WAKEUP 1 +#define USB_FEATURE_TEST_MODE 2 + + +#define USB_HS_MAX_PACKET_SIZE 512 +#define USB_FS_MAX_PACKET_SIZE 64 +#define USB_MAX_EP0_SIZE 64 + +/* Device Status */ +#define USBD_STATE_DEFAULT 1 +#define USBD_STATE_ADDRESSED 2 +#define USBD_STATE_CONFIGURED 3 +#define USBD_STATE_SUSPENDED 4 + + +/* EP0 State */ +#define USBD_EP0_IDLE 0 +#define USBD_EP0_SETUP 1 +#define USBD_EP0_DATA_IN 2 +#define USBD_EP0_DATA_OUT 3 +#define USBD_EP0_STATUS_IN 4 +#define USBD_EP0_STATUS_OUT 5 +#define USBD_EP0_STALL 6 + +#define USBD_EP_TYPE_CTRL 0 +#define USBD_EP_TYPE_ISOC 1 +#define USBD_EP_TYPE_BULK 2 +#define USBD_EP_TYPE_INTR 3 + + +/** + * @} + */ + + +/** @defgroup USBD_DEF_Exported_TypesDefinitions + * @{ + */ + +typedef struct usb_setup_req +{ + + uint8_t bmRequest; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +}USBD_SetupReqTypedef; + +struct _USBD_HandleTypeDef; + +typedef struct _Device_cb +{ + uint8_t (*Init) (struct _USBD_HandleTypeDef *pdev , uint8_t cfgidx); + uint8_t (*DeInit) (struct _USBD_HandleTypeDef *pdev , uint8_t cfgidx); + /* Control Endpoints*/ + uint8_t (*Setup) (struct _USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req); + uint8_t (*EP0_TxSent) (struct _USBD_HandleTypeDef *pdev ); + uint8_t (*EP0_RxReady) (struct _USBD_HandleTypeDef *pdev ); + /* Class Specific Endpoints*/ + uint8_t (*DataIn) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); + uint8_t (*DataOut) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); + uint8_t (*SOF) (struct _USBD_HandleTypeDef *pdev); + uint8_t (*IsoINIncomplete) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); + uint8_t (*IsoOUTIncomplete) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); + + uint8_t *(*GetHSConfigDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); + uint8_t *(*GetFSConfigDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); + uint8_t *(*GetOtherSpeedConfigDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); + uint8_t *(*GetDeviceQualifierDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); + +} USBD_ClassTypeDef; + +/* Following USB Device Speed */ +typedef enum +{ + USBD_SPEED_HIGH = 0, + USBD_SPEED_FULL = 1, + USBD_SPEED_LOW = 2, +}USBD_SpeedTypeDef; + +/* Following USB Device status */ +typedef enum { + USBD_OK = 0, + USBD_BUSY, + USBD_FAIL, +}USBD_StatusTypeDef; + +struct _USBD_HandleTypeDef; + +/* USB Device descriptors structure */ +typedef struct +{ + uint8_t *(*GetDeviceDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); + uint8_t *(*GetStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint8_t idx, uint16_t *length); +} USBD_DescriptorsTypeDef; + +/* USB Device handle structure */ +typedef struct +{ + uint32_t status; + uint32_t total_length; + uint32_t rem_length; + uint32_t maxpacket; +} USBD_EndpointTypeDef; + +/* USB Device handle structure */ +typedef struct _USBD_HandleTypeDef +{ + uint8_t id; + uint32_t dev_config; + uint32_t dev_default_config; + uint32_t dev_config_status; + USBD_SpeedTypeDef dev_speed; + USBD_EndpointTypeDef ep_in[15]; + USBD_EndpointTypeDef ep_out[15]; + uint32_t ep0_state; + uint32_t ep0_data_len; + uint8_t dev_state; + uint8_t dev_old_state; + uint8_t dev_address; + uint8_t dev_connection_status; + uint8_t dev_test_mode; + uint32_t dev_remote_wakeup; + + USBD_SetupReqTypedef request; + USBD_DescriptorsTypeDef *pDesc; + const USBD_ClassTypeDef *pClass; + void *pClassData; + void *pUserData; + void *pData; +} USBD_HandleTypeDef; + +/** + * @} + */ + + + +/** @defgroup USBD_DEF_Exported_Macros + * @{ + */ +#define SWAPBYTE(addr) (((uint16_t)(*((uint8_t *)(addr)))) + \ + (((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8)) + +#define LOBYTE(x) ((uint8_t)(x & 0x00FF)) +#define HIBYTE(x) ((uint8_t)((x & 0xFF00) >>8)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + + +#if defined ( __GNUC__ ) + #ifndef __weak + #define __weak __attribute__((weak)) + #endif /* __weak */ + #ifndef __packed + #define __packed __attribute__((__packed__)) + #endif /* __packed */ +#endif /* __GNUC__ */ + + +/* In HS mode and when the DMA is used, all variables and data structures dealing + with the DMA during the transaction process should be 4-bytes aligned */ + +#if defined (__GNUC__) /* GNU Compiler */ + #define __ALIGN_END __attribute__ ((aligned (4))) + #define __ALIGN_BEGIN +#else + #define __ALIGN_END + #if defined (__CC_ARM) /* ARM Compiler */ + #define __ALIGN_BEGIN __align(4) + #elif defined (__ICCARM__) /* IAR Compiler */ + #define __ALIGN_BEGIN + #elif defined (__TASKING__) /* TASKING Compiler */ + #define __ALIGN_BEGIN __align(4) + #endif /* __CC_ARM */ +#endif /* __GNUC__ */ + + +/** + * @} + */ + +/** @defgroup USBD_DEF_Exported_Variables + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_DEF_Exported_FunctionsPrototype + * @{ + */ + +/** + * @} + */ + +#endif /* __USBD_DEF_H */ + +/** + * @} + */ + +/** +* @} +*/ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/usbdev/core/inc/usbd_ioreq.h b/ports/stm32/usbdev/core/inc/usbd_ioreq.h index 04e01b854b..c964f0ad5a 100644 --- a/ports/stm32/usbdev/core/inc/usbd_ioreq.h +++ b/ports/stm32/usbdev/core/inc/usbd_ioreq.h @@ -1,121 +1,121 @@ -/** - ****************************************************************************** - * @file usbd_ioreq.h - * @author MCD Application Team - * @version V2.0.0 - * @date 18-February-2014 - * @brief header file for the usbd_ioreq.c file - ****************************************************************************** - * @attention - * - *

© COPYRIGHT 2014 STMicroelectronics

- * - * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.st.com/software_license_agreement_liberty_v2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ - -#ifndef __USBD_IOREQ_H_ -#define __USBD_IOREQ_H_ - -/* Includes ------------------------------------------------------------------*/ -#include "usbd_def.h" -#include "usbd_core.h" - -/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY - * @{ - */ - -/** @defgroup USBD_IOREQ - * @brief header file for the usbd_ioreq.c file - * @{ - */ - -/** @defgroup USBD_IOREQ_Exported_Defines - * @{ - */ -/** - * @} - */ - - -/** @defgroup USBD_IOREQ_Exported_Types - * @{ - */ - - -/** - * @} - */ - - - -/** @defgroup USBD_IOREQ_Exported_Macros - * @{ - */ - -/** - * @} - */ - -/** @defgroup USBD_IOREQ_Exported_Variables - * @{ - */ - -/** - * @} - */ - -/** @defgroup USBD_IOREQ_Exported_FunctionsPrototype - * @{ - */ - -USBD_StatusTypeDef USBD_CtlSendData (USBD_HandleTypeDef *pdev, - uint8_t *buf, - uint16_t len); - -USBD_StatusTypeDef USBD_CtlContinueSendData (USBD_HandleTypeDef *pdev, - uint8_t *pbuf, - uint16_t len); - -USBD_StatusTypeDef USBD_CtlPrepareRx (USBD_HandleTypeDef *pdev, - uint8_t *pbuf, - uint16_t len); - -USBD_StatusTypeDef USBD_CtlContinueRx (USBD_HandleTypeDef *pdev, - uint8_t *pbuf, - uint16_t len); - -USBD_StatusTypeDef USBD_CtlSendStatus (USBD_HandleTypeDef *pdev); - -USBD_StatusTypeDef USBD_CtlReceiveStatus (USBD_HandleTypeDef *pdev); - -uint16_t USBD_GetRxCount (USBD_HandleTypeDef *pdev , - uint8_t epnum); - -/** - * @} - */ - -#endif /* __USBD_IOREQ_H_ */ - -/** - * @} - */ - -/** -* @} -*/ -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +/** + ****************************************************************************** + * @file usbd_ioreq.h + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief header file for the usbd_ioreq.c file + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ + +#ifndef __USBD_IOREQ_H_ +#define __USBD_IOREQ_H_ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_def.h" +#include "usbd_core.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USBD_IOREQ + * @brief header file for the usbd_ioreq.c file + * @{ + */ + +/** @defgroup USBD_IOREQ_Exported_Defines + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Exported_Types + * @{ + */ + + +/** + * @} + */ + + + +/** @defgroup USBD_IOREQ_Exported_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_IOREQ_Exported_Variables + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_IOREQ_Exported_FunctionsPrototype + * @{ + */ + +USBD_StatusTypeDef USBD_CtlSendData (USBD_HandleTypeDef *pdev, + uint8_t *buf, + uint16_t len); + +USBD_StatusTypeDef USBD_CtlContinueSendData (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len); + +USBD_StatusTypeDef USBD_CtlPrepareRx (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len); + +USBD_StatusTypeDef USBD_CtlContinueRx (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len); + +USBD_StatusTypeDef USBD_CtlSendStatus (USBD_HandleTypeDef *pdev); + +USBD_StatusTypeDef USBD_CtlReceiveStatus (USBD_HandleTypeDef *pdev); + +uint16_t USBD_GetRxCount (USBD_HandleTypeDef *pdev , + uint8_t epnum); + +/** + * @} + */ + +#endif /* __USBD_IOREQ_H_ */ + +/** + * @} + */ + +/** +* @} +*/ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/usbdev/core/src/usbd_core.c b/ports/stm32/usbdev/core/src/usbd_core.c index 0097036633..f235b24ee6 100644 --- a/ports/stm32/usbdev/core/src/usbd_core.c +++ b/ports/stm32/usbdev/core/src/usbd_core.c @@ -1,552 +1,552 @@ -/** - ****************************************************************************** - * @file usbd_core.c - * @author MCD Application Team - * @version V2.0.0 - * @date 18-February-2014 - * @brief This file provides all the USBD core functions. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT 2014 STMicroelectronics

- * - * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.st.com/software_license_agreement_liberty_v2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ****************************************************************************** - */ - -/* Includes ------------------------------------------------------------------*/ -#include "usbd_core.h" - -/** @addtogroup STM32_USBD_DEVICE_LIBRARY -* @{ -*/ - - -/** @defgroup USBD_CORE -* @brief usbd core module -* @{ -*/ - -/** @defgroup USBD_CORE_Private_TypesDefinitions -* @{ -*/ -/** -* @} -*/ - - -/** @defgroup USBD_CORE_Private_Defines -* @{ -*/ - -/** -* @} -*/ - - -/** @defgroup USBD_CORE_Private_Macros -* @{ -*/ -/** -* @} -*/ - - - - -/** @defgroup USBD_CORE_Private_FunctionPrototypes -* @{ -*/ - -/** -* @} -*/ - -/** @defgroup USBD_CORE_Private_Variables -* @{ -*/ - -/** -* @} -*/ - -/** @defgroup USBD_CORE_Private_Functions -* @{ -*/ - -/** -* @brief USBD_Init -* Initailizes the device stack and load the class driver -* @param pdev: device instance -* @param core_address: USB OTG core ID -* @param pdesc: Descriptor structure address -* @param id: Low level core index -* @retval None -*/ -USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev, USBD_DescriptorsTypeDef *pdesc, uint8_t id) -{ - /* Check whether the USB Host handle is valid */ - if(pdev == NULL) - { - return USBD_FAIL; - } - - /* Unlink previous class*/ - if(pdev->pClass != NULL) - { - pdev->pClass = NULL; - } - - /* Assign USBD Descriptors */ - if(pdesc != NULL) - { - pdev->pDesc = pdesc; - } - - /* Set Device initial State */ - pdev->dev_state = USBD_STATE_DEFAULT; - pdev->id = id; - /* Initialize low level driver */ - USBD_LL_Init(pdev, 0); - - return USBD_OK; -} - -/** -* @brief USBD_DeInit -* Re-Initialize th device library -* @param pdev: device instance -* @retval status: status -*/ -USBD_StatusTypeDef USBD_DeInit(USBD_HandleTypeDef *pdev) -{ - /* Set Default State */ - pdev->dev_state = USBD_STATE_DEFAULT; - - /* Free Class Resources */ - pdev->pClass->DeInit(pdev, pdev->dev_config); - - /* Stop the low level driver */ - USBD_LL_Stop(pdev); - - /* Initialize low level driver */ - USBD_LL_DeInit(pdev); - - return USBD_OK; -} - - -/** - * @brief USBD_RegisterClass - * Link class driver to Device Core. - * @param pDevice : Device Handle - * @param pclass: Class handle - * @retval USBD Status - */ -USBD_StatusTypeDef USBD_RegisterClass(USBD_HandleTypeDef *pdev, const USBD_ClassTypeDef *pclass) -{ - USBD_StatusTypeDef status = USBD_OK; - if(pclass != 0) - { - /* link the class tgo the USB Device handle */ - pdev->pClass = pclass; - status = USBD_OK; - } - else - { - status = USBD_FAIL; - } - - return status; -} - -/** - * @brief USBD_Start - * Start the USB Device Core. - * @param pdev: Device Handle - * @retval USBD Status - */ -USBD_StatusTypeDef USBD_Start (USBD_HandleTypeDef *pdev) -{ - - /* Start the low level driver */ - USBD_LL_Start(pdev); - - return USBD_OK; -} - -/** - * @brief USBD_Stop - * Stop the USB Device Core. - * @param pdev: Device Handle - * @retval USBD Status - */ -USBD_StatusTypeDef USBD_Stop (USBD_HandleTypeDef *pdev) -{ - /* Free Class Resources */ - pdev->pClass->DeInit(pdev, pdev->dev_config); - - /* Stop the low level driver */ - USBD_LL_Stop(pdev); - - return USBD_OK; -} - -/** -* @brief USBD_RunTestMode -* Launch test mode process -* @param pdev: device instance -* @retval status -*/ -USBD_StatusTypeDef USBD_RunTestMode (USBD_HandleTypeDef *pdev) -{ - return USBD_OK; -} - - -/** -* @brief USBD_SetClassConfig -* Configure device and start the interface -* @param pdev: device instance -* @param cfgidx: configuration index -* @retval status -*/ - -USBD_StatusTypeDef USBD_SetClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx) -{ - USBD_StatusTypeDef ret = USBD_FAIL; - - if(pdev->pClass != NULL) - { - /* Set configuration and Start the Class*/ - if(pdev->pClass->Init(pdev, cfgidx) == 0) - { - ret = USBD_OK; - } - } - return ret; -} - -/** -* @brief USBD_ClrClassConfig -* Clear current configuration -* @param pdev: device instance -* @param cfgidx: configuration index -* @retval status: USBD_StatusTypeDef -*/ -USBD_StatusTypeDef USBD_ClrClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx) -{ - /* Clear configuration and Deinitialize the Class process*/ - pdev->pClass->DeInit(pdev, cfgidx); - return USBD_OK; -} - - -/** -* @brief USBD_SetupStage -* Handle the setup stage -* @param pdev: device instance -* @retval status -*/ -USBD_StatusTypeDef USBD_LL_SetupStage(USBD_HandleTypeDef *pdev, uint8_t *psetup) -{ - - USBD_ParseSetupRequest(&pdev->request, psetup); - - pdev->ep0_state = USBD_EP0_SETUP; - pdev->ep0_data_len = pdev->request.wLength; - - switch (pdev->request.bmRequest & 0x1F) - { - case USB_REQ_RECIPIENT_DEVICE: - USBD_StdDevReq (pdev, &pdev->request); - break; - - case USB_REQ_RECIPIENT_INTERFACE: - USBD_StdItfReq(pdev, &pdev->request); - break; - - case USB_REQ_RECIPIENT_ENDPOINT: - USBD_StdEPReq(pdev, &pdev->request); - break; - - default: - USBD_LL_StallEP(pdev , pdev->request.bmRequest & 0x80); - break; - } - return USBD_OK; -} - -/** -* @brief USBD_DataOutStage -* Handle data OUT stage -* @param pdev: device instance -* @param epnum: endpoint index -* @retval status -*/ -USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata) -{ - USBD_EndpointTypeDef *pep; - - if(epnum == 0) - { - pep = &pdev->ep_out[0]; - - if ( pdev->ep0_state == USBD_EP0_DATA_OUT) - { - if(pep->rem_length > pep->maxpacket) - { - pep->rem_length -= pep->maxpacket; - - USBD_CtlContinueRx (pdev, - pdata, - MIN(pep->rem_length ,pep->maxpacket)); - } - else - { - if((pdev->pClass->EP0_RxReady != NULL)&& - (pdev->dev_state == USBD_STATE_CONFIGURED)) - { - pdev->pClass->EP0_RxReady(pdev); - } - USBD_CtlSendStatus(pdev); - } - } - } - else if((pdev->pClass->DataOut != NULL)&& - (pdev->dev_state == USBD_STATE_CONFIGURED)) - { - pdev->pClass->DataOut(pdev, epnum); - } - return USBD_OK; -} - -/** -* @brief USBD_DataInStage -* Handle data in stage -* @param pdev: device instance -* @param epnum: endpoint index -* @retval status -*/ -USBD_StatusTypeDef USBD_LL_DataInStage(USBD_HandleTypeDef *pdev ,uint8_t epnum, uint8_t *pdata) -{ - USBD_EndpointTypeDef *pep; - - if(epnum == 0) - { - pep = &pdev->ep_in[0]; - - if ( pdev->ep0_state == USBD_EP0_DATA_IN) - { - if(pep->rem_length > pep->maxpacket) - { - pep->rem_length -= pep->maxpacket; - - USBD_CtlContinueSendData (pdev, - pdata, - pep->rem_length); - } - else - { /* last packet is MPS multiple, so send ZLP packet */ - if((pep->total_length % pep->maxpacket == 0) && - (pep->total_length >= pep->maxpacket) && - (pep->total_length < pdev->ep0_data_len )) - { - - USBD_CtlContinueSendData(pdev , NULL, 0); - pdev->ep0_data_len = 0; - } - else - { - if((pdev->pClass->EP0_TxSent != NULL)&& - (pdev->dev_state == USBD_STATE_CONFIGURED)) - { - pdev->pClass->EP0_TxSent(pdev); - } - USBD_CtlReceiveStatus(pdev); - } - } - } - if (pdev->dev_test_mode == 1) - { - USBD_RunTestMode(pdev); - pdev->dev_test_mode = 0; - } - } - else if((pdev->pClass->DataIn != NULL)&& - (pdev->dev_state == USBD_STATE_CONFIGURED)) - { - pdev->pClass->DataIn(pdev, epnum); - } - return USBD_OK; -} - -/** -* @brief USBD_LL_Reset -* Handle Reset event -* @param pdev: device instance -* @retval status -*/ - -USBD_StatusTypeDef USBD_LL_Reset(USBD_HandleTypeDef *pdev) -{ - /* Open EP0 OUT */ - USBD_LL_OpenEP(pdev, - 0x00, - USBD_EP_TYPE_CTRL, - USB_MAX_EP0_SIZE); - - pdev->ep_out[0].maxpacket = USB_MAX_EP0_SIZE; - - /* Open EP0 IN */ - USBD_LL_OpenEP(pdev, - 0x80, - USBD_EP_TYPE_CTRL, - USB_MAX_EP0_SIZE); - - pdev->ep_in[0].maxpacket = USB_MAX_EP0_SIZE; - /* Upon Reset call usr call back */ - pdev->dev_state = USBD_STATE_DEFAULT; - - if (pdev->pClassData) - pdev->pClass->DeInit(pdev, pdev->dev_config); - - - return USBD_OK; -} - - - - -/** -* @brief USBD_LL_Reset -* Handle Reset event -* @param pdev: device instance -* @retval status -*/ -USBD_StatusTypeDef USBD_LL_SetSpeed(USBD_HandleTypeDef *pdev, USBD_SpeedTypeDef speed) -{ - pdev->dev_speed = speed; - return USBD_OK; -} - -/** -* @brief USBD_Suspend -* Handle Suspend event -* @param pdev: device instance -* @retval status -*/ - -USBD_StatusTypeDef USBD_LL_Suspend(USBD_HandleTypeDef *pdev) -{ - pdev->dev_old_state = pdev->dev_state; - pdev->dev_state = USBD_STATE_SUSPENDED; - return USBD_OK; -} - -/** -* @brief USBD_Resume -* Handle Resume event -* @param pdev: device instance -* @retval status -*/ - -USBD_StatusTypeDef USBD_LL_Resume(USBD_HandleTypeDef *pdev) -{ - pdev->dev_state = pdev->dev_old_state; - return USBD_OK; -} - -/** -* @brief USBD_SOF -* Handle SOF event -* @param pdev: device instance -* @retval status -*/ - -USBD_StatusTypeDef USBD_LL_SOF(USBD_HandleTypeDef *pdev) -{ - if(pdev->dev_state == USBD_STATE_CONFIGURED) - { - if(pdev->pClass->SOF != NULL) - { - pdev->pClass->SOF(pdev); - } - } - return USBD_OK; -} - -/** -* @brief USBD_IsoINIncomplete -* Handle iso in incomplete event -* @param pdev: device instance -* @retval status -*/ -USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum) -{ - return USBD_OK; -} - -/** -* @brief USBD_IsoOUTIncomplete -* Handle iso out incomplete event -* @param pdev: device instance -* @retval status -*/ -USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum) -{ - return USBD_OK; -} - -/** -* @brief USBD_DevConnected -* Handle device connection event -* @param pdev: device instance -* @retval status -*/ -USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev) -{ - return USBD_OK; -} - -/** -* @brief USBD_DevDisconnected -* Handle device disconnection event -* @param pdev: device instance -* @retval status -*/ -USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev) -{ - /* Free Class Resources */ - pdev->dev_state = USBD_STATE_DEFAULT; - pdev->pClass->DeInit(pdev, pdev->dev_config); - - return USBD_OK; -} -/** -* @} -*/ - - -/** -* @} -*/ - - -/** -* @} -*/ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ - +/** + ****************************************************************************** + * @file usbd_core.c + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief This file provides all the USBD core functions. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_core.h" + +/** @addtogroup STM32_USBD_DEVICE_LIBRARY +* @{ +*/ + + +/** @defgroup USBD_CORE +* @brief usbd core module +* @{ +*/ + +/** @defgroup USBD_CORE_Private_TypesDefinitions +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBD_CORE_Private_Defines +* @{ +*/ + +/** +* @} +*/ + + +/** @defgroup USBD_CORE_Private_Macros +* @{ +*/ +/** +* @} +*/ + + + + +/** @defgroup USBD_CORE_Private_FunctionPrototypes +* @{ +*/ + +/** +* @} +*/ + +/** @defgroup USBD_CORE_Private_Variables +* @{ +*/ + +/** +* @} +*/ + +/** @defgroup USBD_CORE_Private_Functions +* @{ +*/ + +/** +* @brief USBD_Init +* Initailizes the device stack and load the class driver +* @param pdev: device instance +* @param core_address: USB OTG core ID +* @param pdesc: Descriptor structure address +* @param id: Low level core index +* @retval None +*/ +USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev, USBD_DescriptorsTypeDef *pdesc, uint8_t id) +{ + /* Check whether the USB Host handle is valid */ + if(pdev == NULL) + { + return USBD_FAIL; + } + + /* Unlink previous class*/ + if(pdev->pClass != NULL) + { + pdev->pClass = NULL; + } + + /* Assign USBD Descriptors */ + if(pdesc != NULL) + { + pdev->pDesc = pdesc; + } + + /* Set Device initial State */ + pdev->dev_state = USBD_STATE_DEFAULT; + pdev->id = id; + /* Initialize low level driver */ + USBD_LL_Init(pdev, 0); + + return USBD_OK; +} + +/** +* @brief USBD_DeInit +* Re-Initialize th device library +* @param pdev: device instance +* @retval status: status +*/ +USBD_StatusTypeDef USBD_DeInit(USBD_HandleTypeDef *pdev) +{ + /* Set Default State */ + pdev->dev_state = USBD_STATE_DEFAULT; + + /* Free Class Resources */ + pdev->pClass->DeInit(pdev, pdev->dev_config); + + /* Stop the low level driver */ + USBD_LL_Stop(pdev); + + /* Initialize low level driver */ + USBD_LL_DeInit(pdev); + + return USBD_OK; +} + + +/** + * @brief USBD_RegisterClass + * Link class driver to Device Core. + * @param pDevice : Device Handle + * @param pclass: Class handle + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_RegisterClass(USBD_HandleTypeDef *pdev, const USBD_ClassTypeDef *pclass) +{ + USBD_StatusTypeDef status = USBD_OK; + if(pclass != 0) + { + /* link the class tgo the USB Device handle */ + pdev->pClass = pclass; + status = USBD_OK; + } + else + { + status = USBD_FAIL; + } + + return status; +} + +/** + * @brief USBD_Start + * Start the USB Device Core. + * @param pdev: Device Handle + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_Start (USBD_HandleTypeDef *pdev) +{ + + /* Start the low level driver */ + USBD_LL_Start(pdev); + + return USBD_OK; +} + +/** + * @brief USBD_Stop + * Stop the USB Device Core. + * @param pdev: Device Handle + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_Stop (USBD_HandleTypeDef *pdev) +{ + /* Free Class Resources */ + pdev->pClass->DeInit(pdev, pdev->dev_config); + + /* Stop the low level driver */ + USBD_LL_Stop(pdev); + + return USBD_OK; +} + +/** +* @brief USBD_RunTestMode +* Launch test mode process +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_RunTestMode (USBD_HandleTypeDef *pdev) +{ + return USBD_OK; +} + + +/** +* @brief USBD_SetClassConfig +* Configure device and start the interface +* @param pdev: device instance +* @param cfgidx: configuration index +* @retval status +*/ + +USBD_StatusTypeDef USBD_SetClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx) +{ + USBD_StatusTypeDef ret = USBD_FAIL; + + if(pdev->pClass != NULL) + { + /* Set configuration and Start the Class*/ + if(pdev->pClass->Init(pdev, cfgidx) == 0) + { + ret = USBD_OK; + } + } + return ret; +} + +/** +* @brief USBD_ClrClassConfig +* Clear current configuration +* @param pdev: device instance +* @param cfgidx: configuration index +* @retval status: USBD_StatusTypeDef +*/ +USBD_StatusTypeDef USBD_ClrClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx) +{ + /* Clear configuration and Deinitialize the Class process*/ + pdev->pClass->DeInit(pdev, cfgidx); + return USBD_OK; +} + + +/** +* @brief USBD_SetupStage +* Handle the setup stage +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_SetupStage(USBD_HandleTypeDef *pdev, uint8_t *psetup) +{ + + USBD_ParseSetupRequest(&pdev->request, psetup); + + pdev->ep0_state = USBD_EP0_SETUP; + pdev->ep0_data_len = pdev->request.wLength; + + switch (pdev->request.bmRequest & 0x1F) + { + case USB_REQ_RECIPIENT_DEVICE: + USBD_StdDevReq (pdev, &pdev->request); + break; + + case USB_REQ_RECIPIENT_INTERFACE: + USBD_StdItfReq(pdev, &pdev->request); + break; + + case USB_REQ_RECIPIENT_ENDPOINT: + USBD_StdEPReq(pdev, &pdev->request); + break; + + default: + USBD_LL_StallEP(pdev , pdev->request.bmRequest & 0x80); + break; + } + return USBD_OK; +} + +/** +* @brief USBD_DataOutStage +* Handle data OUT stage +* @param pdev: device instance +* @param epnum: endpoint index +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata) +{ + USBD_EndpointTypeDef *pep; + + if(epnum == 0) + { + pep = &pdev->ep_out[0]; + + if ( pdev->ep0_state == USBD_EP0_DATA_OUT) + { + if(pep->rem_length > pep->maxpacket) + { + pep->rem_length -= pep->maxpacket; + + USBD_CtlContinueRx (pdev, + pdata, + MIN(pep->rem_length ,pep->maxpacket)); + } + else + { + if((pdev->pClass->EP0_RxReady != NULL)&& + (pdev->dev_state == USBD_STATE_CONFIGURED)) + { + pdev->pClass->EP0_RxReady(pdev); + } + USBD_CtlSendStatus(pdev); + } + } + } + else if((pdev->pClass->DataOut != NULL)&& + (pdev->dev_state == USBD_STATE_CONFIGURED)) + { + pdev->pClass->DataOut(pdev, epnum); + } + return USBD_OK; +} + +/** +* @brief USBD_DataInStage +* Handle data in stage +* @param pdev: device instance +* @param epnum: endpoint index +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_DataInStage(USBD_HandleTypeDef *pdev ,uint8_t epnum, uint8_t *pdata) +{ + USBD_EndpointTypeDef *pep; + + if(epnum == 0) + { + pep = &pdev->ep_in[0]; + + if ( pdev->ep0_state == USBD_EP0_DATA_IN) + { + if(pep->rem_length > pep->maxpacket) + { + pep->rem_length -= pep->maxpacket; + + USBD_CtlContinueSendData (pdev, + pdata, + pep->rem_length); + } + else + { /* last packet is MPS multiple, so send ZLP packet */ + if((pep->total_length % pep->maxpacket == 0) && + (pep->total_length >= pep->maxpacket) && + (pep->total_length < pdev->ep0_data_len )) + { + + USBD_CtlContinueSendData(pdev , NULL, 0); + pdev->ep0_data_len = 0; + } + else + { + if((pdev->pClass->EP0_TxSent != NULL)&& + (pdev->dev_state == USBD_STATE_CONFIGURED)) + { + pdev->pClass->EP0_TxSent(pdev); + } + USBD_CtlReceiveStatus(pdev); + } + } + } + if (pdev->dev_test_mode == 1) + { + USBD_RunTestMode(pdev); + pdev->dev_test_mode = 0; + } + } + else if((pdev->pClass->DataIn != NULL)&& + (pdev->dev_state == USBD_STATE_CONFIGURED)) + { + pdev->pClass->DataIn(pdev, epnum); + } + return USBD_OK; +} + +/** +* @brief USBD_LL_Reset +* Handle Reset event +* @param pdev: device instance +* @retval status +*/ + +USBD_StatusTypeDef USBD_LL_Reset(USBD_HandleTypeDef *pdev) +{ + /* Open EP0 OUT */ + USBD_LL_OpenEP(pdev, + 0x00, + USBD_EP_TYPE_CTRL, + USB_MAX_EP0_SIZE); + + pdev->ep_out[0].maxpacket = USB_MAX_EP0_SIZE; + + /* Open EP0 IN */ + USBD_LL_OpenEP(pdev, + 0x80, + USBD_EP_TYPE_CTRL, + USB_MAX_EP0_SIZE); + + pdev->ep_in[0].maxpacket = USB_MAX_EP0_SIZE; + /* Upon Reset call usr call back */ + pdev->dev_state = USBD_STATE_DEFAULT; + + if (pdev->pClassData) + pdev->pClass->DeInit(pdev, pdev->dev_config); + + + return USBD_OK; +} + + + + +/** +* @brief USBD_LL_Reset +* Handle Reset event +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_SetSpeed(USBD_HandleTypeDef *pdev, USBD_SpeedTypeDef speed) +{ + pdev->dev_speed = speed; + return USBD_OK; +} + +/** +* @brief USBD_Suspend +* Handle Suspend event +* @param pdev: device instance +* @retval status +*/ + +USBD_StatusTypeDef USBD_LL_Suspend(USBD_HandleTypeDef *pdev) +{ + pdev->dev_old_state = pdev->dev_state; + pdev->dev_state = USBD_STATE_SUSPENDED; + return USBD_OK; +} + +/** +* @brief USBD_Resume +* Handle Resume event +* @param pdev: device instance +* @retval status +*/ + +USBD_StatusTypeDef USBD_LL_Resume(USBD_HandleTypeDef *pdev) +{ + pdev->dev_state = pdev->dev_old_state; + return USBD_OK; +} + +/** +* @brief USBD_SOF +* Handle SOF event +* @param pdev: device instance +* @retval status +*/ + +USBD_StatusTypeDef USBD_LL_SOF(USBD_HandleTypeDef *pdev) +{ + if(pdev->dev_state == USBD_STATE_CONFIGURED) + { + if(pdev->pClass->SOF != NULL) + { + pdev->pClass->SOF(pdev); + } + } + return USBD_OK; +} + +/** +* @brief USBD_IsoINIncomplete +* Handle iso in incomplete event +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum) +{ + return USBD_OK; +} + +/** +* @brief USBD_IsoOUTIncomplete +* Handle iso out incomplete event +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum) +{ + return USBD_OK; +} + +/** +* @brief USBD_DevConnected +* Handle device connection event +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev) +{ + return USBD_OK; +} + +/** +* @brief USBD_DevDisconnected +* Handle device disconnection event +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev) +{ + /* Free Class Resources */ + pdev->dev_state = USBD_STATE_DEFAULT; + pdev->pClass->DeInit(pdev, pdev->dev_config); + + return USBD_OK; +} +/** +* @} +*/ + + +/** +* @} +*/ + + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/ports/stm32/usbdev/core/src/usbd_ctlreq.c b/ports/stm32/usbdev/core/src/usbd_ctlreq.c index a68016bf45..f25f252d64 100644 --- a/ports/stm32/usbdev/core/src/usbd_ctlreq.c +++ b/ports/stm32/usbdev/core/src/usbd_ctlreq.c @@ -1,740 +1,740 @@ -/** - ****************************************************************************** - * @file usbd_req.c - * @author MCD Application Team - * @version V2.0.0 - * @date 18-February-2014 - * @brief This file provides the standard USB requests following chapter 9. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT 2014 STMicroelectronics

- * - * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.st.com/software_license_agreement_liberty_v2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ****************************************************************************** - */ - -/* Includes ------------------------------------------------------------------*/ -#include "usbd_ctlreq.h" -#include "usbd_ioreq.h" - - -/** @addtogroup STM32_USBD_STATE_DEVICE_LIBRARY - * @{ - */ - - -/** @defgroup USBD_REQ - * @brief USB standard requests module - * @{ - */ - -/** @defgroup USBD_REQ_Private_TypesDefinitions - * @{ - */ -/** - * @} - */ - - -/** @defgroup USBD_REQ_Private_Defines - * @{ - */ - -/** - * @} - */ - - -/** @defgroup USBD_REQ_Private_Macros - * @{ - */ -/** - * @} - */ - - -/** @defgroup USBD_REQ_Private_Variables - * @{ - */ -/** - * @} - */ - - -/** @defgroup USBD_REQ_Private_FunctionPrototypes - * @{ - */ -static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev , - USBD_SetupReqTypedef *req); - -static void USBD_SetAddress(USBD_HandleTypeDef *pdev , - USBD_SetupReqTypedef *req); - -static void USBD_SetConfig(USBD_HandleTypeDef *pdev , - USBD_SetupReqTypedef *req); - -static void USBD_GetConfig(USBD_HandleTypeDef *pdev , - USBD_SetupReqTypedef *req); - -static void USBD_GetStatus(USBD_HandleTypeDef *pdev , - USBD_SetupReqTypedef *req); - -static void USBD_SetFeature(USBD_HandleTypeDef *pdev , - USBD_SetupReqTypedef *req); - -static void USBD_ClrFeature(USBD_HandleTypeDef *pdev , - USBD_SetupReqTypedef *req); - -static uint8_t USBD_GetLen(uint8_t *buf); - -/** - * @} - */ - - -/** @defgroup USBD_REQ_Private_Functions - * @{ - */ - - -/** -* @brief USBD_StdDevReq -* Handle standard usb device requests -* @param pdev: device instance -* @param req: usb request -* @retval status -*/ -USBD_StatusTypeDef USBD_StdDevReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req) -{ - USBD_StatusTypeDef ret = USBD_OK; - - switch (req->bRequest) - { - case USB_REQ_GET_DESCRIPTOR: - - USBD_GetDescriptor (pdev, req) ; - break; - - case USB_REQ_SET_ADDRESS: - USBD_SetAddress(pdev, req); - break; - - case USB_REQ_SET_CONFIGURATION: - USBD_SetConfig (pdev , req); - break; - - case USB_REQ_GET_CONFIGURATION: - USBD_GetConfig (pdev , req); - break; - - case USB_REQ_GET_STATUS: - USBD_GetStatus (pdev , req); - break; - - - case USB_REQ_SET_FEATURE: - USBD_SetFeature (pdev , req); - break; - - case USB_REQ_CLEAR_FEATURE: - USBD_ClrFeature (pdev , req); - break; - - default: - USBD_CtlError(pdev , req); - break; - } - - return ret; -} - -/** -* @brief USBD_StdItfReq -* Handle standard usb interface requests -* @param pdev: USB OTG device instance -* @param req: usb request -* @retval status -*/ -USBD_StatusTypeDef USBD_StdItfReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req) -{ - USBD_StatusTypeDef ret = USBD_OK; - - switch (pdev->dev_state) - { - case USBD_STATE_CONFIGURED: - - if (LOBYTE(req->wIndex) <= USBD_MAX_NUM_INTERFACES) - { - pdev->pClass->Setup (pdev, req); - - if((req->wLength == 0)&& (ret == USBD_OK)) - { - USBD_CtlSendStatus(pdev); - } - } - else - { - USBD_CtlError(pdev , req); - } - break; - - default: - USBD_CtlError(pdev , req); - break; - } - return USBD_OK; -} - -/** -* @brief USBD_StdEPReq -* Handle standard usb endpoint requests -* @param pdev: USB OTG device instance -* @param req: usb request -* @retval status -*/ -USBD_StatusTypeDef USBD_StdEPReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req) -{ - - uint8_t ep_addr; - USBD_StatusTypeDef ret = USBD_OK; - USBD_EndpointTypeDef *pep; - ep_addr = LOBYTE(req->wIndex); - - switch (req->bRequest) - { - - case USB_REQ_SET_FEATURE : - - switch (pdev->dev_state) - { - case USBD_STATE_ADDRESSED: - if ((ep_addr != 0x00) && (ep_addr != 0x80)) - { - USBD_LL_StallEP(pdev , ep_addr); - } - break; - - case USBD_STATE_CONFIGURED: - if (req->wValue == USB_FEATURE_EP_HALT) - { - if ((ep_addr != 0x00) && (ep_addr != 0x80)) - { - USBD_LL_StallEP(pdev , ep_addr); - - } - } - pdev->pClass->Setup (pdev, req); - USBD_CtlSendStatus(pdev); - - break; - - default: - USBD_CtlError(pdev , req); - break; - } - break; - - case USB_REQ_CLEAR_FEATURE : - - switch (pdev->dev_state) - { - case USBD_STATE_ADDRESSED: - if ((ep_addr != 0x00) && (ep_addr != 0x80)) - { - USBD_LL_StallEP(pdev , ep_addr); - } - break; - - case USBD_STATE_CONFIGURED: - if (req->wValue == USB_FEATURE_EP_HALT) - { - if ((ep_addr & 0x7F) != 0x00) - { - USBD_LL_ClearStallEP(pdev , ep_addr); - pdev->pClass->Setup (pdev, req); - } - USBD_CtlSendStatus(pdev); - } - break; - - default: - USBD_CtlError(pdev , req); - break; - } - break; - - case USB_REQ_GET_STATUS: - switch (pdev->dev_state) - { - case USBD_STATE_ADDRESSED: - if ((ep_addr & 0x7F) != 0x00) - { - USBD_LL_StallEP(pdev , ep_addr); - } - break; - - case USBD_STATE_CONFIGURED: - pep = ((ep_addr & 0x80) == 0x80) ? &pdev->ep_in[ep_addr & 0x7F]:\ - &pdev->ep_out[ep_addr & 0x7F]; - if(USBD_LL_IsStallEP(pdev, ep_addr)) - { - pep->status = 0x0001; - } - else - { - pep->status = 0x0000; - } - - USBD_CtlSendData (pdev, - (uint8_t *)&pep->status, - 2); - break; - - default: - USBD_CtlError(pdev , req); - break; - } - break; - - default: - break; - } - return ret; -} -/** -* @brief USBD_GetDescriptor -* Handle Get Descriptor requests -* @param pdev: device instance -* @param req: usb request -* @retval status -*/ -static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev , - USBD_SetupReqTypedef *req) -{ - uint16_t len; - uint8_t *pbuf; - - - switch (req->wValue >> 8) - { - case USB_DESC_TYPE_DEVICE: - pbuf = pdev->pDesc->GetDeviceDescriptor(pdev, &len); - break; - - case USB_DESC_TYPE_CONFIGURATION: - if(pdev->dev_speed == USBD_SPEED_HIGH ) - { - pbuf = (uint8_t *)pdev->pClass->GetHSConfigDescriptor(pdev, &len); - pbuf[1] = USB_DESC_TYPE_CONFIGURATION; - } - else - { - pbuf = (uint8_t *)pdev->pClass->GetFSConfigDescriptor(pdev, &len); - pbuf[1] = USB_DESC_TYPE_CONFIGURATION; - } - break; - - case USB_DESC_TYPE_STRING: - pbuf = pdev->pDesc->GetStrDescriptor(pdev, req->wValue & 0xff, &len); - if (pbuf == NULL) { - USBD_CtlError(pdev, req); - return; - } - break; - - case USB_DESC_TYPE_DEVICE_QUALIFIER: - - if(pdev->dev_speed == USBD_SPEED_HIGH ) - { - pbuf = (uint8_t *)pdev->pClass->GetDeviceQualifierDescriptor(pdev, &len); - break; - } - else - { - USBD_CtlError(pdev , req); - return; - } - - case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION: - if(pdev->dev_speed == USBD_SPEED_HIGH ) - { - pbuf = (uint8_t *)pdev->pClass->GetOtherSpeedConfigDescriptor(pdev, &len); - pbuf[1] = USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION; - break; - } - else - { - USBD_CtlError(pdev , req); - return; - } - - default: - USBD_CtlError(pdev , req); - return; - } - - if((len != 0)&& (req->wLength != 0)) - { - - len = MIN(len , req->wLength); - - USBD_CtlSendData (pdev, - pbuf, - len); - } - -} - -/** -* @brief USBD_SetAddress -* Set device address -* @param pdev: device instance -* @param req: usb request -* @retval status -*/ -static void USBD_SetAddress(USBD_HandleTypeDef *pdev , - USBD_SetupReqTypedef *req) -{ - uint8_t dev_addr; - - if ((req->wIndex == 0) && (req->wLength == 0)) - { - dev_addr = (uint8_t)(req->wValue) & 0x7F; - - if (pdev->dev_state == USBD_STATE_CONFIGURED) - { - USBD_CtlError(pdev , req); - } - else - { - pdev->dev_address = dev_addr; - USBD_LL_SetUSBAddress(pdev, dev_addr); - USBD_CtlSendStatus(pdev); - - if (dev_addr != 0) - { - pdev->dev_state = USBD_STATE_ADDRESSED; - } - else - { - pdev->dev_state = USBD_STATE_DEFAULT; - } - } - } - else - { - USBD_CtlError(pdev , req); - } -} - -/** -* @brief USBD_SetConfig -* Handle Set device configuration request -* @param pdev: device instance -* @param req: usb request -* @retval status -*/ -static void USBD_SetConfig(USBD_HandleTypeDef *pdev , - USBD_SetupReqTypedef *req) -{ - - uint8_t cfgidx; - - cfgidx = (uint8_t)(req->wValue); - - if (cfgidx > USBD_MAX_NUM_CONFIGURATION ) - { - USBD_CtlError(pdev , req); - } - else - { - switch (pdev->dev_state) - { - case USBD_STATE_ADDRESSED: - if (cfgidx) - { - pdev->dev_config = cfgidx; - pdev->dev_state = USBD_STATE_CONFIGURED; - if(USBD_SetClassConfig(pdev , cfgidx) == USBD_FAIL) - { - USBD_CtlError(pdev , req); - return; - } - USBD_CtlSendStatus(pdev); - } - else - { - USBD_CtlSendStatus(pdev); - } - break; - - case USBD_STATE_CONFIGURED: - if (cfgidx == 0) - { - pdev->dev_state = USBD_STATE_ADDRESSED; - pdev->dev_config = cfgidx; - USBD_ClrClassConfig(pdev , cfgidx); - USBD_CtlSendStatus(pdev); - - } - else if (cfgidx != pdev->dev_config) - { - /* Clear old configuration */ - USBD_ClrClassConfig(pdev , pdev->dev_config); - - /* set new configuration */ - pdev->dev_config = cfgidx; - if(USBD_SetClassConfig(pdev , cfgidx) == USBD_FAIL) - { - USBD_CtlError(pdev , req); - return; - } - USBD_CtlSendStatus(pdev); - } - else - { - USBD_CtlSendStatus(pdev); - } - break; - - default: - USBD_CtlError(pdev , req); - break; - } - } -} - -/** -* @brief USBD_GetConfig -* Handle Get device configuration request -* @param pdev: device instance -* @param req: usb request -* @retval status -*/ -static void USBD_GetConfig(USBD_HandleTypeDef *pdev , - USBD_SetupReqTypedef *req) -{ - - if (req->wLength != 1) - { - USBD_CtlError(pdev , req); - } - else - { - switch (pdev->dev_state ) - { - case USBD_STATE_ADDRESSED: - pdev->dev_default_config = 0; - USBD_CtlSendData (pdev, - (uint8_t *)&pdev->dev_default_config, - 1); - break; - - case USBD_STATE_CONFIGURED: - - USBD_CtlSendData (pdev, - (uint8_t *)&pdev->dev_config, - 1); - break; - - default: - USBD_CtlError(pdev , req); - break; - } - } -} - -/** -* @brief USBD_GetStatus -* Handle Get Status request -* @param pdev: device instance -* @param req: usb request -* @retval status -*/ -static void USBD_GetStatus(USBD_HandleTypeDef *pdev , - USBD_SetupReqTypedef *req) -{ - - - switch (pdev->dev_state) - { - case USBD_STATE_ADDRESSED: - case USBD_STATE_CONFIGURED: - -#if ( USBD_SELF_POWERED == 1) - pdev->dev_config_status = USB_CONFIG_SELF_POWERED; -#else - pdev->dev_config_status = 0; -#endif - - if (pdev->dev_remote_wakeup) - { - pdev->dev_config_status |= USB_CONFIG_REMOTE_WAKEUP; - } - - USBD_CtlSendData (pdev, - (uint8_t *)& pdev->dev_config_status, - 2); - break; - - default : - USBD_CtlError(pdev , req); - break; - } -} - - -/** -* @brief USBD_SetFeature -* Handle Set device feature request -* @param pdev: device instance -* @param req: usb request -* @retval status -*/ -static void USBD_SetFeature(USBD_HandleTypeDef *pdev , - USBD_SetupReqTypedef *req) -{ - - if (req->wValue == USB_FEATURE_REMOTE_WAKEUP) - { - pdev->dev_remote_wakeup = 1; - pdev->pClass->Setup (pdev, req); - USBD_CtlSendStatus(pdev); - } - -} - - -/** -* @brief USBD_ClrFeature -* Handle clear device feature request -* @param pdev: device instance -* @param req: usb request -* @retval status -*/ -static void USBD_ClrFeature(USBD_HandleTypeDef *pdev , - USBD_SetupReqTypedef *req) -{ - switch (pdev->dev_state) - { - case USBD_STATE_ADDRESSED: - case USBD_STATE_CONFIGURED: - if (req->wValue == USB_FEATURE_REMOTE_WAKEUP) - { - pdev->dev_remote_wakeup = 0; - pdev->pClass->Setup (pdev, req); - USBD_CtlSendStatus(pdev); - } - break; - - default : - USBD_CtlError(pdev , req); - break; - } -} - -/** -* @brief USBD_ParseSetupRequest -* Copy buffer into setup structure -* @param pdev: device instance -* @param req: usb request -* @retval None -*/ - -void USBD_ParseSetupRequest(USBD_SetupReqTypedef *req, uint8_t *pdata) -{ - req->bmRequest = *(uint8_t *) (pdata); - req->bRequest = *(uint8_t *) (pdata + 1); - req->wValue = SWAPBYTE (pdata + 2); - req->wIndex = SWAPBYTE (pdata + 4); - req->wLength = SWAPBYTE (pdata + 6); - -} - -/** -* @brief USBD_CtlError -* Handle USB low level Error -* @param pdev: device instance -* @param req: usb request -* @retval None -*/ - -void USBD_CtlError( USBD_HandleTypeDef *pdev , - USBD_SetupReqTypedef *req) -{ - USBD_LL_StallEP(pdev , 0x80); - USBD_LL_StallEP(pdev , 0); -} - - -/** - * @brief USBD_GetString - * Convert Ascii string into unicode one - * @param desc : descriptor buffer - * @param unicode : Formatted string buffer (unicode) - * @param len : descriptor length - * @retval None - */ -void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t *len) -{ - uint8_t idx = 0; - - if (desc != NULL) - { - *len = USBD_GetLen(desc) * 2 + 2; - unicode[idx++] = *len; - unicode[idx++] = USB_DESC_TYPE_STRING; - - while (*desc != '\0') - { - unicode[idx++] = *desc++; - unicode[idx++] = 0x00; - } - } -} - -/** - * @brief USBD_GetLen - * return the string length - * @param buf : pointer to the ascii string buffer - * @retval string length - */ -static uint8_t USBD_GetLen(uint8_t *buf) -{ - uint8_t len = 0; - - while (*buf != '\0') - { - len++; - buf++; - } - - return len; -} -/** - * @} - */ - - -/** - * @} - */ - - -/** - * @} - */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +/** + ****************************************************************************** + * @file usbd_req.c + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief This file provides the standard USB requests following chapter 9. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_ctlreq.h" +#include "usbd_ioreq.h" + + +/** @addtogroup STM32_USBD_STATE_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup USBD_REQ + * @brief USB standard requests module + * @{ + */ + +/** @defgroup USBD_REQ_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_Variables + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_FunctionPrototypes + * @{ + */ +static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_SetAddress(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_SetConfig(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_GetConfig(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_GetStatus(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_SetFeature(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_ClrFeature(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static uint8_t USBD_GetLen(uint8_t *buf); + +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_Functions + * @{ + */ + + +/** +* @brief USBD_StdDevReq +* Handle standard usb device requests +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +USBD_StatusTypeDef USBD_StdDevReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req) +{ + USBD_StatusTypeDef ret = USBD_OK; + + switch (req->bRequest) + { + case USB_REQ_GET_DESCRIPTOR: + + USBD_GetDescriptor (pdev, req) ; + break; + + case USB_REQ_SET_ADDRESS: + USBD_SetAddress(pdev, req); + break; + + case USB_REQ_SET_CONFIGURATION: + USBD_SetConfig (pdev , req); + break; + + case USB_REQ_GET_CONFIGURATION: + USBD_GetConfig (pdev , req); + break; + + case USB_REQ_GET_STATUS: + USBD_GetStatus (pdev , req); + break; + + + case USB_REQ_SET_FEATURE: + USBD_SetFeature (pdev , req); + break; + + case USB_REQ_CLEAR_FEATURE: + USBD_ClrFeature (pdev , req); + break; + + default: + USBD_CtlError(pdev , req); + break; + } + + return ret; +} + +/** +* @brief USBD_StdItfReq +* Handle standard usb interface requests +* @param pdev: USB OTG device instance +* @param req: usb request +* @retval status +*/ +USBD_StatusTypeDef USBD_StdItfReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req) +{ + USBD_StatusTypeDef ret = USBD_OK; + + switch (pdev->dev_state) + { + case USBD_STATE_CONFIGURED: + + if (LOBYTE(req->wIndex) <= USBD_MAX_NUM_INTERFACES) + { + pdev->pClass->Setup (pdev, req); + + if((req->wLength == 0)&& (ret == USBD_OK)) + { + USBD_CtlSendStatus(pdev); + } + } + else + { + USBD_CtlError(pdev , req); + } + break; + + default: + USBD_CtlError(pdev , req); + break; + } + return USBD_OK; +} + +/** +* @brief USBD_StdEPReq +* Handle standard usb endpoint requests +* @param pdev: USB OTG device instance +* @param req: usb request +* @retval status +*/ +USBD_StatusTypeDef USBD_StdEPReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req) +{ + + uint8_t ep_addr; + USBD_StatusTypeDef ret = USBD_OK; + USBD_EndpointTypeDef *pep; + ep_addr = LOBYTE(req->wIndex); + + switch (req->bRequest) + { + + case USB_REQ_SET_FEATURE : + + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + if ((ep_addr != 0x00) && (ep_addr != 0x80)) + { + USBD_LL_StallEP(pdev , ep_addr); + } + break; + + case USBD_STATE_CONFIGURED: + if (req->wValue == USB_FEATURE_EP_HALT) + { + if ((ep_addr != 0x00) && (ep_addr != 0x80)) + { + USBD_LL_StallEP(pdev , ep_addr); + + } + } + pdev->pClass->Setup (pdev, req); + USBD_CtlSendStatus(pdev); + + break; + + default: + USBD_CtlError(pdev , req); + break; + } + break; + + case USB_REQ_CLEAR_FEATURE : + + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + if ((ep_addr != 0x00) && (ep_addr != 0x80)) + { + USBD_LL_StallEP(pdev , ep_addr); + } + break; + + case USBD_STATE_CONFIGURED: + if (req->wValue == USB_FEATURE_EP_HALT) + { + if ((ep_addr & 0x7F) != 0x00) + { + USBD_LL_ClearStallEP(pdev , ep_addr); + pdev->pClass->Setup (pdev, req); + } + USBD_CtlSendStatus(pdev); + } + break; + + default: + USBD_CtlError(pdev , req); + break; + } + break; + + case USB_REQ_GET_STATUS: + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + if ((ep_addr & 0x7F) != 0x00) + { + USBD_LL_StallEP(pdev , ep_addr); + } + break; + + case USBD_STATE_CONFIGURED: + pep = ((ep_addr & 0x80) == 0x80) ? &pdev->ep_in[ep_addr & 0x7F]:\ + &pdev->ep_out[ep_addr & 0x7F]; + if(USBD_LL_IsStallEP(pdev, ep_addr)) + { + pep->status = 0x0001; + } + else + { + pep->status = 0x0000; + } + + USBD_CtlSendData (pdev, + (uint8_t *)&pep->status, + 2); + break; + + default: + USBD_CtlError(pdev , req); + break; + } + break; + + default: + break; + } + return ret; +} +/** +* @brief USBD_GetDescriptor +* Handle Get Descriptor requests +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + uint16_t len; + uint8_t *pbuf; + + + switch (req->wValue >> 8) + { + case USB_DESC_TYPE_DEVICE: + pbuf = pdev->pDesc->GetDeviceDescriptor(pdev, &len); + break; + + case USB_DESC_TYPE_CONFIGURATION: + if(pdev->dev_speed == USBD_SPEED_HIGH ) + { + pbuf = (uint8_t *)pdev->pClass->GetHSConfigDescriptor(pdev, &len); + pbuf[1] = USB_DESC_TYPE_CONFIGURATION; + } + else + { + pbuf = (uint8_t *)pdev->pClass->GetFSConfigDescriptor(pdev, &len); + pbuf[1] = USB_DESC_TYPE_CONFIGURATION; + } + break; + + case USB_DESC_TYPE_STRING: + pbuf = pdev->pDesc->GetStrDescriptor(pdev, req->wValue & 0xff, &len); + if (pbuf == NULL) { + USBD_CtlError(pdev, req); + return; + } + break; + + case USB_DESC_TYPE_DEVICE_QUALIFIER: + + if(pdev->dev_speed == USBD_SPEED_HIGH ) + { + pbuf = (uint8_t *)pdev->pClass->GetDeviceQualifierDescriptor(pdev, &len); + break; + } + else + { + USBD_CtlError(pdev , req); + return; + } + + case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION: + if(pdev->dev_speed == USBD_SPEED_HIGH ) + { + pbuf = (uint8_t *)pdev->pClass->GetOtherSpeedConfigDescriptor(pdev, &len); + pbuf[1] = USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION; + break; + } + else + { + USBD_CtlError(pdev , req); + return; + } + + default: + USBD_CtlError(pdev , req); + return; + } + + if((len != 0)&& (req->wLength != 0)) + { + + len = MIN(len , req->wLength); + + USBD_CtlSendData (pdev, + pbuf, + len); + } + +} + +/** +* @brief USBD_SetAddress +* Set device address +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_SetAddress(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + uint8_t dev_addr; + + if ((req->wIndex == 0) && (req->wLength == 0)) + { + dev_addr = (uint8_t)(req->wValue) & 0x7F; + + if (pdev->dev_state == USBD_STATE_CONFIGURED) + { + USBD_CtlError(pdev , req); + } + else + { + pdev->dev_address = dev_addr; + USBD_LL_SetUSBAddress(pdev, dev_addr); + USBD_CtlSendStatus(pdev); + + if (dev_addr != 0) + { + pdev->dev_state = USBD_STATE_ADDRESSED; + } + else + { + pdev->dev_state = USBD_STATE_DEFAULT; + } + } + } + else + { + USBD_CtlError(pdev , req); + } +} + +/** +* @brief USBD_SetConfig +* Handle Set device configuration request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_SetConfig(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + + uint8_t cfgidx; + + cfgidx = (uint8_t)(req->wValue); + + if (cfgidx > USBD_MAX_NUM_CONFIGURATION ) + { + USBD_CtlError(pdev , req); + } + else + { + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + if (cfgidx) + { + pdev->dev_config = cfgidx; + pdev->dev_state = USBD_STATE_CONFIGURED; + if(USBD_SetClassConfig(pdev , cfgidx) == USBD_FAIL) + { + USBD_CtlError(pdev , req); + return; + } + USBD_CtlSendStatus(pdev); + } + else + { + USBD_CtlSendStatus(pdev); + } + break; + + case USBD_STATE_CONFIGURED: + if (cfgidx == 0) + { + pdev->dev_state = USBD_STATE_ADDRESSED; + pdev->dev_config = cfgidx; + USBD_ClrClassConfig(pdev , cfgidx); + USBD_CtlSendStatus(pdev); + + } + else if (cfgidx != pdev->dev_config) + { + /* Clear old configuration */ + USBD_ClrClassConfig(pdev , pdev->dev_config); + + /* set new configuration */ + pdev->dev_config = cfgidx; + if(USBD_SetClassConfig(pdev , cfgidx) == USBD_FAIL) + { + USBD_CtlError(pdev , req); + return; + } + USBD_CtlSendStatus(pdev); + } + else + { + USBD_CtlSendStatus(pdev); + } + break; + + default: + USBD_CtlError(pdev , req); + break; + } + } +} + +/** +* @brief USBD_GetConfig +* Handle Get device configuration request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_GetConfig(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + + if (req->wLength != 1) + { + USBD_CtlError(pdev , req); + } + else + { + switch (pdev->dev_state ) + { + case USBD_STATE_ADDRESSED: + pdev->dev_default_config = 0; + USBD_CtlSendData (pdev, + (uint8_t *)&pdev->dev_default_config, + 1); + break; + + case USBD_STATE_CONFIGURED: + + USBD_CtlSendData (pdev, + (uint8_t *)&pdev->dev_config, + 1); + break; + + default: + USBD_CtlError(pdev , req); + break; + } + } +} + +/** +* @brief USBD_GetStatus +* Handle Get Status request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_GetStatus(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + + + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + case USBD_STATE_CONFIGURED: + +#if ( USBD_SELF_POWERED == 1) + pdev->dev_config_status = USB_CONFIG_SELF_POWERED; +#else + pdev->dev_config_status = 0; +#endif + + if (pdev->dev_remote_wakeup) + { + pdev->dev_config_status |= USB_CONFIG_REMOTE_WAKEUP; + } + + USBD_CtlSendData (pdev, + (uint8_t *)& pdev->dev_config_status, + 2); + break; + + default : + USBD_CtlError(pdev , req); + break; + } +} + + +/** +* @brief USBD_SetFeature +* Handle Set device feature request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_SetFeature(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + + if (req->wValue == USB_FEATURE_REMOTE_WAKEUP) + { + pdev->dev_remote_wakeup = 1; + pdev->pClass->Setup (pdev, req); + USBD_CtlSendStatus(pdev); + } + +} + + +/** +* @brief USBD_ClrFeature +* Handle clear device feature request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_ClrFeature(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + case USBD_STATE_CONFIGURED: + if (req->wValue == USB_FEATURE_REMOTE_WAKEUP) + { + pdev->dev_remote_wakeup = 0; + pdev->pClass->Setup (pdev, req); + USBD_CtlSendStatus(pdev); + } + break; + + default : + USBD_CtlError(pdev , req); + break; + } +} + +/** +* @brief USBD_ParseSetupRequest +* Copy buffer into setup structure +* @param pdev: device instance +* @param req: usb request +* @retval None +*/ + +void USBD_ParseSetupRequest(USBD_SetupReqTypedef *req, uint8_t *pdata) +{ + req->bmRequest = *(uint8_t *) (pdata); + req->bRequest = *(uint8_t *) (pdata + 1); + req->wValue = SWAPBYTE (pdata + 2); + req->wIndex = SWAPBYTE (pdata + 4); + req->wLength = SWAPBYTE (pdata + 6); + +} + +/** +* @brief USBD_CtlError +* Handle USB low level Error +* @param pdev: device instance +* @param req: usb request +* @retval None +*/ + +void USBD_CtlError( USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + USBD_LL_StallEP(pdev , 0x80); + USBD_LL_StallEP(pdev , 0); +} + + +/** + * @brief USBD_GetString + * Convert Ascii string into unicode one + * @param desc : descriptor buffer + * @param unicode : Formatted string buffer (unicode) + * @param len : descriptor length + * @retval None + */ +void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t *len) +{ + uint8_t idx = 0; + + if (desc != NULL) + { + *len = USBD_GetLen(desc) * 2 + 2; + unicode[idx++] = *len; + unicode[idx++] = USB_DESC_TYPE_STRING; + + while (*desc != '\0') + { + unicode[idx++] = *desc++; + unicode[idx++] = 0x00; + } + } +} + +/** + * @brief USBD_GetLen + * return the string length + * @param buf : pointer to the ascii string buffer + * @retval string length + */ +static uint8_t USBD_GetLen(uint8_t *buf) +{ + uint8_t len = 0; + + while (*buf != '\0') + { + len++; + buf++; + } + + return len; +} +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/usbdev/core/src/usbd_ioreq.c b/ports/stm32/usbdev/core/src/usbd_ioreq.c index 9e396ba566..aab59fcef5 100644 --- a/ports/stm32/usbdev/core/src/usbd_ioreq.c +++ b/ports/stm32/usbdev/core/src/usbd_ioreq.c @@ -1,236 +1,236 @@ -/** - ****************************************************************************** - * @file usbd_ioreq.c - * @author MCD Application Team - * @version V2.0.0 - * @date 18-February-2014 - * @brief This file provides the IO requests APIs for control endpoints. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT 2014 STMicroelectronics

- * - * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.st.com/software_license_agreement_liberty_v2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ****************************************************************************** - */ - -/* Includes ------------------------------------------------------------------*/ -#include "usbd_ioreq.h" - -/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY - * @{ - */ - - -/** @defgroup USBD_IOREQ - * @brief control I/O requests module - * @{ - */ - -/** @defgroup USBD_IOREQ_Private_TypesDefinitions - * @{ - */ -/** - * @} - */ - - -/** @defgroup USBD_IOREQ_Private_Defines - * @{ - */ - -/** - * @} - */ - - -/** @defgroup USBD_IOREQ_Private_Macros - * @{ - */ -/** - * @} - */ - - -/** @defgroup USBD_IOREQ_Private_Variables - * @{ - */ - -/** - * @} - */ - - -/** @defgroup USBD_IOREQ_Private_FunctionPrototypes - * @{ - */ -/** - * @} - */ - - -/** @defgroup USBD_IOREQ_Private_Functions - * @{ - */ - -/** -* @brief USBD_CtlSendData -* send data on the ctl pipe -* @param pdev: device instance -* @param buff: pointer to data buffer -* @param len: length of data to be sent -* @retval status -*/ -USBD_StatusTypeDef USBD_CtlSendData (USBD_HandleTypeDef *pdev, - uint8_t *pbuf, - uint16_t len) -{ - /* Set EP0 State */ - pdev->ep0_state = USBD_EP0_DATA_IN; - pdev->ep_in[0].total_length = len; - pdev->ep_in[0].rem_length = len; - /* Start the transfer */ - USBD_LL_Transmit (pdev, 0x00, pbuf, len); - - return USBD_OK; -} - -/** -* @brief USBD_CtlContinueSendData -* continue sending data on the ctl pipe -* @param pdev: device instance -* @param buff: pointer to data buffer -* @param len: length of data to be sent -* @retval status -*/ -USBD_StatusTypeDef USBD_CtlContinueSendData (USBD_HandleTypeDef *pdev, - uint8_t *pbuf, - uint16_t len) -{ - /* Start the next transfer */ - USBD_LL_Transmit (pdev, 0x00, pbuf, len); - - return USBD_OK; -} - -/** -* @brief USBD_CtlPrepareRx -* receive data on the ctl pipe -* @param pdev: USB OTG device instance -* @param buff: pointer to data buffer -* @param len: length of data to be received -* @retval status -*/ -USBD_StatusTypeDef USBD_CtlPrepareRx (USBD_HandleTypeDef *pdev, - uint8_t *pbuf, - uint16_t len) -{ - /* Set EP0 State */ - pdev->ep0_state = USBD_EP0_DATA_OUT; - pdev->ep_out[0].total_length = len; - pdev->ep_out[0].rem_length = len; - /* Start the transfer */ - USBD_LL_PrepareReceive (pdev, - 0, - pbuf, - len); - - return USBD_OK; -} - -/** -* @brief USBD_CtlContinueRx -* continue receive data on the ctl pipe -* @param pdev: USB OTG device instance -* @param buff: pointer to data buffer -* @param len: length of data to be received -* @retval status -*/ -USBD_StatusTypeDef USBD_CtlContinueRx (USBD_HandleTypeDef *pdev, - uint8_t *pbuf, - uint16_t len) -{ - - USBD_LL_PrepareReceive (pdev, - 0, - pbuf, - len); - return USBD_OK; -} -/** -* @brief USBD_CtlSendStatus -* send zero lzngth packet on the ctl pipe -* @param pdev: USB OTG device instance -* @retval status -*/ -USBD_StatusTypeDef USBD_CtlSendStatus (USBD_HandleTypeDef *pdev) -{ - - /* Set EP0 State */ - pdev->ep0_state = USBD_EP0_STATUS_IN; - - /* Start the transfer */ - USBD_LL_Transmit (pdev, 0x00, NULL, 0); - - return USBD_OK; -} - -/** -* @brief USBD_CtlReceiveStatus -* receive zero lzngth packet on the ctl pipe -* @param pdev: USB OTG device instance -* @retval status -*/ -USBD_StatusTypeDef USBD_CtlReceiveStatus (USBD_HandleTypeDef *pdev) -{ - /* Set EP0 State */ - pdev->ep0_state = USBD_EP0_STATUS_OUT; - - /* Start the transfer */ - USBD_LL_PrepareReceive ( pdev, - 0, - NULL, - 0); - - return USBD_OK; -} - - -/** -* @brief USBD_GetRxCount -* returns the received data length -* @param pdev: USB OTG device instance -* epnum: endpoint index -* @retval Rx Data blength -*/ -uint16_t USBD_GetRxCount (USBD_HandleTypeDef *pdev , uint8_t ep_addr) -{ - return USBD_LL_GetRxDataSize(pdev, ep_addr); -} - -/** - * @} - */ - - -/** - * @} - */ - - -/** - * @} - */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +/** + ****************************************************************************** + * @file usbd_ioreq.c + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief This file provides the IO requests APIs for control endpoints. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_ioreq.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup USBD_IOREQ + * @brief control I/O requests module + * @{ + */ + +/** @defgroup USBD_IOREQ_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Private_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Private_Variables + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Private_FunctionPrototypes + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Private_Functions + * @{ + */ + +/** +* @brief USBD_CtlSendData +* send data on the ctl pipe +* @param pdev: device instance +* @param buff: pointer to data buffer +* @param len: length of data to be sent +* @retval status +*/ +USBD_StatusTypeDef USBD_CtlSendData (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len) +{ + /* Set EP0 State */ + pdev->ep0_state = USBD_EP0_DATA_IN; + pdev->ep_in[0].total_length = len; + pdev->ep_in[0].rem_length = len; + /* Start the transfer */ + USBD_LL_Transmit (pdev, 0x00, pbuf, len); + + return USBD_OK; +} + +/** +* @brief USBD_CtlContinueSendData +* continue sending data on the ctl pipe +* @param pdev: device instance +* @param buff: pointer to data buffer +* @param len: length of data to be sent +* @retval status +*/ +USBD_StatusTypeDef USBD_CtlContinueSendData (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len) +{ + /* Start the next transfer */ + USBD_LL_Transmit (pdev, 0x00, pbuf, len); + + return USBD_OK; +} + +/** +* @brief USBD_CtlPrepareRx +* receive data on the ctl pipe +* @param pdev: USB OTG device instance +* @param buff: pointer to data buffer +* @param len: length of data to be received +* @retval status +*/ +USBD_StatusTypeDef USBD_CtlPrepareRx (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len) +{ + /* Set EP0 State */ + pdev->ep0_state = USBD_EP0_DATA_OUT; + pdev->ep_out[0].total_length = len; + pdev->ep_out[0].rem_length = len; + /* Start the transfer */ + USBD_LL_PrepareReceive (pdev, + 0, + pbuf, + len); + + return USBD_OK; +} + +/** +* @brief USBD_CtlContinueRx +* continue receive data on the ctl pipe +* @param pdev: USB OTG device instance +* @param buff: pointer to data buffer +* @param len: length of data to be received +* @retval status +*/ +USBD_StatusTypeDef USBD_CtlContinueRx (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len) +{ + + USBD_LL_PrepareReceive (pdev, + 0, + pbuf, + len); + return USBD_OK; +} +/** +* @brief USBD_CtlSendStatus +* send zero lzngth packet on the ctl pipe +* @param pdev: USB OTG device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_CtlSendStatus (USBD_HandleTypeDef *pdev) +{ + + /* Set EP0 State */ + pdev->ep0_state = USBD_EP0_STATUS_IN; + + /* Start the transfer */ + USBD_LL_Transmit (pdev, 0x00, NULL, 0); + + return USBD_OK; +} + +/** +* @brief USBD_CtlReceiveStatus +* receive zero lzngth packet on the ctl pipe +* @param pdev: USB OTG device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_CtlReceiveStatus (USBD_HandleTypeDef *pdev) +{ + /* Set EP0 State */ + pdev->ep0_state = USBD_EP0_STATUS_OUT; + + /* Start the transfer */ + USBD_LL_PrepareReceive ( pdev, + 0, + NULL, + 0); + + return USBD_OK; +} + + +/** +* @brief USBD_GetRxCount +* returns the received data length +* @param pdev: USB OTG device instance +* epnum: endpoint index +* @retval Rx Data blength +*/ +uint16_t USBD_GetRxCount (USBD_HandleTypeDef *pdev , uint8_t ep_addr) +{ + return USBD_LL_GetRxDataSize(pdev, ep_addr); +} + +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ From 4b3c6290678a6b812179deb23eb23cb0632a09ff Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 11 May 2018 23:07:57 +1000 Subject: [PATCH 636/828] .gitattributes: Remove special text handling of stm32 usbdev files. --- .gitattributes | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitattributes b/.gitattributes index 133e2625c1..fdd31021f7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -16,8 +16,6 @@ tests/basics/string_cr_conversion.py -text tests/basics/string_crlf_conversion.py -text ports/stm32/pybcdc.inf_template -text -ports/stm32/usbd_* -text -ports/stm32/usbdev/** -text ports/stm32/usbhost/** -text ports/cc3200/hal/aes.c -text ports/cc3200/hal/aes.h -text From aeaace0737f5c2c305f163d6d61617cfd7faf4ce Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 11 May 2018 23:20:59 +1000 Subject: [PATCH 637/828] stm32/usbdev: Remove unused RxState variable, and unused struct. --- ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h | 9 --------- ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 1 - 2 files changed, 10 deletions(-) diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h index 2177127019..1ff22ba904 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -44,20 +44,11 @@ #define CDC_OUT_EP (0x03) #define CDC_CMD_EP (0x82) -typedef struct { - uint32_t bitrate; - uint8_t format; - uint8_t paritytype; - uint8_t datatype; -} USBD_CDC_LineCodingTypeDef; - typedef struct { uint32_t data[CDC_DATA_MAX_PACKET_SIZE / 4]; // Force 32bits alignment uint8_t CmdOpCode; uint8_t CmdLength; - volatile uint32_t TxState; - volatile uint32_t RxState; } USBD_CDC_HandleTypeDef; typedef struct _USBD_STORAGE { diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c index a1a7cff6c1..369c5457e8 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -706,7 +706,6 @@ static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { // Init Xfer states usbd->CDC_ClassData.TxState = 0; - usbd->CDC_ClassData.RxState = 0; // Prepare Out endpoint to receive next packet USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, buf, mp); From 749b16174b5292b2680ab027a6a1b3874e22ea43 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 12 May 2018 22:09:34 +1000 Subject: [PATCH 638/828] py/mpstate.h: Adjust start of root pointer section to exclude non-ptrs. This patch moves the start of the root pointer section in mp_state_ctx_t so that it skips entries that are not pointers and don't need scanning. Previously, the start of the root pointer section was at the very beginning of the mp_state_ctx_t struct (which is the beginning of mp_state_thread_t). This was the original assembler version of the NLR code was hard-coded to have the nlr_top pointer at the start of this state structure. But now that the NLR code is partially written in C there is no longer this restriction on the location of nlr_top (and a comment to this effect has been removed in this patch). So now the root pointer section starts part way through the mp_state_thread_t structure, after the entries which are not root pointers. This patch also moves the non-pointer entries for MICROPY_ENABLE_SCHEDULER outside the root pointer section. Moving non-pointer entries out of the root pointer section helps to make the GC more precise and should help to prevent some cases of collectable garbage being kept. This patch also has a measurable improvement in performance of the pystone.py benchmark: on unix x86-64 and stm32 there was an improvement of roughly 0.6% (tested with both gcc 7.3 and gcc 8.1). --- py/gc.c | 4 +++- py/mpstate.h | 34 +++++++++++++++++++++------------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/py/gc.c b/py/gc.c index 84c9918fd7..38de513997 100644 --- a/py/gc.c +++ b/py/gc.c @@ -328,7 +328,9 @@ void gc_collect_start(void) { // correctly in the mp_state_ctx structure. We scan nlr_top, dict_locals, // dict_globals, then the root pointer section of mp_state_vm. void **ptrs = (void**)(void*)&mp_state_ctx; - gc_collect_root(ptrs, offsetof(mp_state_ctx_t, vm.qstr_last_chunk) / sizeof(void*)); + size_t root_start = offsetof(mp_state_ctx_t, thread.dict_locals); + size_t root_end = offsetof(mp_state_ctx_t, vm.qstr_last_chunk); + gc_collect_root(ptrs + root_start / sizeof(void*), (root_end - root_start) / sizeof(void*)); #if MICROPY_ENABLE_PYSTACK // Trace root pointers from the Python stack. diff --git a/py/mpstate.h b/py/mpstate.h index 16c4bf6c57..199fd2cb63 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -105,10 +105,11 @@ typedef struct _mp_state_mem_t { // This structure hold runtime and VM information. It includes a section // which contains root pointers that must be scanned by the GC. typedef struct _mp_state_vm_t { - //////////////////////////////////////////////////////////// - // START ROOT POINTER SECTION - // everything that needs GC scanning must go here - // this must start at the start of this structure + // + // CONTINUE ROOT POINTER SECTION + // This must start at the start of this structure and follows + // the state in the mp_state_thread_t structure, continuing + // the root pointer section from there. // qstr_pool_t *last_pool; @@ -139,8 +140,6 @@ typedef struct _mp_state_vm_t { volatile mp_obj_t mp_pending_exception; #if MICROPY_ENABLE_SCHEDULER - volatile int16_t sched_state; - uint16_t sched_sp; mp_sched_item_t sched_stack[MICROPY_SCHEDULER_DEPTH]; #endif @@ -208,6 +207,11 @@ typedef struct _mp_state_vm_t { mp_int_t mp_emergency_exception_buf_size; #endif + #if MICROPY_ENABLE_SCHEDULER + volatile int16_t sched_state; + uint16_t sched_sp; + #endif + #if MICROPY_PY_THREAD_GIL // This is a global mutex used to make the VM/runtime thread-safe. mp_thread_mutex_t gil_mutex; @@ -217,11 +221,6 @@ typedef struct _mp_state_vm_t { // This structure holds state that is specific to a given thread. // Everything in this structure is scanned for root pointers. typedef struct _mp_state_thread_t { - mp_obj_dict_t *dict_locals; - mp_obj_dict_t *dict_globals; - - nlr_buf_t *nlr_top; // ROOT POINTER - // Stack top at the start of program char *stack_top; @@ -234,12 +233,21 @@ typedef struct _mp_state_thread_t { uint8_t *pystack_end; uint8_t *pystack_cur; #endif + + //////////////////////////////////////////////////////////// + // START ROOT POINTER SECTION + // Everything that needs GC scanning must start here, and + // is followed by state in the mp_state_vm_t structure. + // + + mp_obj_dict_t *dict_locals; + mp_obj_dict_t *dict_globals; + + nlr_buf_t *nlr_top; } mp_state_thread_t; // This structure combines the above 3 structures. // The order of the entries are important for root pointer scanning in the GC to work. -// Note: if this structure changes then revisit all nlr asm code since they -// have the offset of nlr_top hard-coded. typedef struct _mp_state_ctx_t { mp_state_thread_t thread; mp_state_vm_t vm; From 67e1a4f8be15dfea0721e4bdf0c8034fc7f83149 Mon Sep 17 00:00:00 2001 From: Bas Wijnen Date: Wed, 9 May 2018 15:27:22 +0200 Subject: [PATCH 639/828] esp32: Update to latest ESP IDF version. - Updated supported git hash to current IDF version. - Added missing targets and includes to Makefile. - Updated error codes for networking module. - Added required constant to sdkconfig configuration. --- ports/esp32/Makefile | 10 +++++++++- ports/esp32/modnetwork.c | 35 ++++++++++++++++++++--------------- ports/esp32/sdkconfig.h | 1 + 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 0d9e074286..304082df9d 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -21,7 +21,7 @@ FLASH_FREQ ?= 40m FLASH_SIZE ?= 4MB CROSS_COMPILE ?= xtensa-esp32-elf- -ESPIDF_SUPHASH := 3ede9f011b50999b0560683f9419538c066dd09e +ESPIDF_SUPHASH := a2556229aa6f55b16b171e3325ee9ab1943e8552 # paths to ESP IDF and its components ifeq ($(ESPIDF),) @@ -92,6 +92,7 @@ INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/port/include INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include INC_ESPCOMP += -I$(ESPCOMP)/app_trace/include INC_ESPCOMP += -I$(ESPCOMP)/app_update/include +INC_ESPCOMP += -I$(ESPCOMP)/pthread/include CFLAGS_BASE = -std=gnu99 -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -mlongcalls -nostdlib -Wall -Werror -Wno-error=unused-function -Wno-error=unused-but-set-variable -Wno-error=unused-variable -Wno-error=deprecated-declarations -DMBEDTLS_CONFIG_FILE='"mbedtls/esp_config.h"' -DHAVE_CONFIG_H -DESP_PLATFORM CFLAGS = $(CFLAGS_BASE) $(INC) $(INC_ESPCOMP) @@ -686,9 +687,14 @@ $(BUILD)/%.o: %.cpp $(BUILD)/bootloader/$(ESPCOMP)/%.o: CFLAGS += -DBOOTLOADER_BUILD=1 -I$(ESPCOMP)/bootloader_support/include_priv -I$(ESPCOMP)/bootloader_support/include -I$(ESPCOMP)/micro-ecc/micro-ecc -I$(ESPCOMP)/esp32 -Wno-error=format BOOTLOADER_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ bootloader_support/src/bootloader_clock.o \ + bootloader_support/src/bootloader_common.o \ bootloader_support/src/bootloader_flash.o \ + bootloader_support/src/bootloader_init.o \ bootloader_support/src/bootloader_random.o \ bootloader_support/src/bootloader_sha.o \ + bootloader_support/src/bootloader_utility.o \ + bootloader_support/src/efuse.o \ + bootloader_support/src/flash_qio_mode.o \ bootloader_support/src/secure_boot_signatures.o \ bootloader_support/src/secure_boot.o \ bootloader_support/src/esp_image_format.o \ @@ -698,6 +704,7 @@ BOOTLOADER_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ spi_flash/spi_flash_rom_patch.o \ soc/esp32/rtc_clk.o \ soc/esp32/rtc_time.o \ + soc/esp32/cpu_util.o \ micro-ecc/micro-ecc/uECC.o \ bootloader/subproject/main/bootloader_start.o \ ) @@ -722,6 +729,7 @@ BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/bootloader/subproject/main/esp32.bootloader. BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/bootloader/subproject/main/esp32.bootloader.rom.ld BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.rom.ld BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.rom.spiram_incompatible_fns.ld +BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.peripherals.ld BOOTLOADER_OBJ_DIRS = $(sort $(dir $(BOOTLOADER_OBJ))) $(BOOTLOADER_OBJ): | $(BOOTLOADER_OBJ_DIRS) diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index 11d50eec32..f3be999a7a 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -59,34 +59,39 @@ NORETURN void _esp_exceptions(esp_err_t e) { mp_raise_msg(&mp_type_OSError, "Wifi Not Initialized"); case ESP_ERR_WIFI_NOT_STARTED: mp_raise_msg(&mp_type_OSError, "Wifi Not Started"); - case ESP_ERR_WIFI_CONN: - mp_raise_msg(&mp_type_OSError, "Wifi Internal Error"); - case ESP_ERR_WIFI_SSID: - mp_raise_msg(&mp_type_OSError, "Wifi SSID Invalid"); - case ESP_ERR_WIFI_FAIL: - mp_raise_msg(&mp_type_OSError, "Wifi Internal Failure"); + case ESP_ERR_WIFI_NOT_STOPPED: + mp_raise_msg(&mp_type_OSError, "Wifi Not Stopped"); case ESP_ERR_WIFI_IF: mp_raise_msg(&mp_type_OSError, "Wifi Invalid Interface"); - case ESP_ERR_WIFI_MAC: - mp_raise_msg(&mp_type_OSError, "Wifi Invalid MAC Address"); - case ESP_ERR_WIFI_ARG: - mp_raise_msg(&mp_type_OSError, "Wifi Invalid Argument"); case ESP_ERR_WIFI_MODE: mp_raise_msg(&mp_type_OSError, "Wifi Invalid Mode"); - case ESP_ERR_WIFI_PASSWORD: - mp_raise_msg(&mp_type_OSError, "Wifi Invalid Password"); + case ESP_ERR_WIFI_STATE: + mp_raise_msg(&mp_type_OSError, "Wifi Internal State Error"); + case ESP_ERR_WIFI_CONN: + mp_raise_msg(&mp_type_OSError, "Wifi Internal Error"); case ESP_ERR_WIFI_NVS: mp_raise_msg(&mp_type_OSError, "Wifi Internal NVS Error"); + case ESP_ERR_WIFI_MAC: + mp_raise_msg(&mp_type_OSError, "Wifi Invalid MAC Address"); + case ESP_ERR_WIFI_SSID: + mp_raise_msg(&mp_type_OSError, "Wifi SSID Invalid"); + case ESP_ERR_WIFI_PASSWORD: + mp_raise_msg(&mp_type_OSError, "Wifi Invalid Password"); + case ESP_ERR_WIFI_TIMEOUT: + mp_raise_OSError(MP_ETIMEDOUT); + case ESP_ERR_WIFI_WAKE_FAIL: + mp_raise_msg(&mp_type_OSError, "Wifi Wakeup Failure"); + case ESP_ERR_WIFI_WOULD_BLOCK: + mp_raise_msg(&mp_type_OSError, "Wifi Would Block"); + case ESP_ERR_WIFI_NOT_CONNECT: + mp_raise_msg(&mp_type_OSError, "Wifi Not Connected"); case ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS: mp_raise_msg(&mp_type_OSError, "TCP/IP Invalid Parameters"); case ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY: mp_raise_msg(&mp_type_OSError, "TCP/IP IF Not Ready"); case ESP_ERR_TCPIP_ADAPTER_DHCPC_START_FAILED: mp_raise_msg(&mp_type_OSError, "TCP/IP DHCP Client Start Failed"); - case ESP_ERR_WIFI_TIMEOUT: - mp_raise_OSError(MP_ETIMEDOUT); case ESP_ERR_TCPIP_ADAPTER_NO_MEM: - case ESP_ERR_WIFI_NO_MEM: mp_raise_OSError(MP_ENOMEM); default: nlr_raise(mp_obj_new_exception_msg_varg( diff --git a/ports/esp32/sdkconfig.h b/ports/esp32/sdkconfig.h index ff25afaf2d..576f1734a8 100644 --- a/ports/esp32/sdkconfig.h +++ b/ports/esp32/sdkconfig.h @@ -24,6 +24,7 @@ #define CONFIG_ESP32_PHY_MAX_TX_POWER 20 #define CONFIG_ESP32_PANIC_PRINT_REBOOT 1 #define CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC 1 +#define CONFIG_ESP32_RTC_XTAL_BOOTSTRAP_CYCLES 100 #define CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 1 #define CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ 240 #define CONFIG_ESP32_DEFAULT_CPU_FREQ_240 1 From 1f1623d3b78edb9f824accb6c7da3c4872bdc1ef Mon Sep 17 00:00:00 2001 From: "Peter D. Gray" Date: Fri, 11 May 2018 11:42:19 -0400 Subject: [PATCH 640/828] stm32/usbdev: Be honest about data not being written to HID endpoint. USB_HID.send() should now return 0 if it could not send the report to the host. --- ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c index 369c5457e8..2e1df0cb76 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -1161,9 +1161,10 @@ uint8_t USBD_HID_SendReport(usbd_cdc_msc_hid_state_t *usbd, uint8_t *report, uin if (usbd->HID_ClassData.state == HID_IDLE) { usbd->HID_ClassData.state = HID_BUSY; USBD_LL_Transmit(usbd->pdev, usbd->hid_in_ep, report, len); + return USBD_OK; } } - return USBD_OK; + return USBD_FAIL; } uint8_t USBD_HID_SetNAK(usbd_cdc_msc_hid_state_t *usbd) { From ca366454103e28d6a85823454e64c21302627555 Mon Sep 17 00:00:00 2001 From: "Peter D. Gray" Date: Fri, 11 May 2018 11:40:04 -0400 Subject: [PATCH 641/828] stm32/usbd_hid_interface: Address possible race condition vs. interrupt. The USB IRQ may fire once USBD_HID_ClearNAK() is called and then change the last_read_len value. --- ports/stm32/usbd_hid_interface.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ports/stm32/usbd_hid_interface.c b/ports/stm32/usbd_hid_interface.c index 4ee533c21c..9ab5986b66 100644 --- a/ports/stm32/usbd_hid_interface.c +++ b/ports/stm32/usbd_hid_interface.c @@ -94,12 +94,13 @@ int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout) } // Copy bytes from device to user buffer - memcpy(buf, hid->buffer[hid->current_read_buffer], hid->last_read_len); + int read_len = hid->last_read_len; + memcpy(buf, hid->buffer[hid->current_read_buffer], read_len); hid->current_read_buffer = !hid->current_read_buffer; // Clear NAK to indicate we are ready to read more data USBD_HID_ClearNAK(hid->usbd); // Success, return number of bytes read - return hid->last_read_len; + return read_len; } From b21415ed4f4bcc66b9a76313e3b47483d279da11 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 14 May 2018 13:19:03 +1000 Subject: [PATCH 642/828] stm32/i2c: Add new hardware I2C driver for F4 MCUs. This driver uses low-level register access to control the I2C peripheral (ie it doesn't rely on the ST HAL) and provides the same C-level API as the existing F7 hardware driver. --- ports/stm32/i2c.c | 240 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 237 insertions(+), 3 deletions(-) diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index 63bd09ae5f..a717ca7b39 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -30,10 +30,240 @@ #if MICROPY_HW_ENABLE_HW_I2C -#if defined(STM32F7) - #define I2C_POLL_TIMEOUT_MS (50) +#if defined(STM32F4) + +int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t freq) { + uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); + + // Init pins + if (!mp_hal_pin_config_alt(scl, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, AF_FN_I2C, i2c_id + 1)) { + return -MP_EPERM; + } + if (!mp_hal_pin_config_alt(sda, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, AF_FN_I2C, i2c_id + 1)) { + return -MP_EPERM; + } + + // Force reset I2C peripheral + RCC->APB1RSTR |= RCC_APB1RSTR_I2C1RST << i2c_id; + RCC->APB1RSTR &= ~(RCC_APB1RSTR_I2C1RST << i2c_id); + + // Enable I2C peripheral clock + RCC->APB1ENR |= RCC_APB1ENR_I2C1EN << i2c_id; + volatile uint32_t tmp = RCC->APB1ENR; // delay after RCC clock enable + (void)tmp; + + uint32_t PCLK1 = HAL_RCC_GetPCLK1Freq(); + + // Initialise I2C peripheral + i2c->CR1 = 0; + i2c->CR2 = PCLK1 / 1000000; + i2c->OAR1 = 0; + i2c->OAR2 = 0; + + freq = MIN(freq, 400000); + + // SM: MAX(4, PCLK1 / (F * 2)) + // FM, 16:9 duty: 0xc000 | MAX(1, (PCLK1 / (F * (16 + 9)))) + if (freq <= 100000) { + i2c->CCR = MAX(4, PCLK1 / (freq * 2)); + } else { + i2c->CCR = 0xc000 | MAX(1, PCLK1 / (freq * 25)); + } + + // SM: 1000ns / (1/PCLK1) + 1 = PCLK1 * 1e-6 + 1 + // FM: 300ns / (1/PCLK1) + 1 = 300e-3 * PCLK1 * 1e-6 + 1 + if (freq <= 100000) { + i2c->TRISE = PCLK1 / 1000000 + 1; // 1000ns rise time in SM + } else { + i2c->TRISE = PCLK1 / 1000000 * 3 / 10 + 1; // 300ns rise time in FM + } + + #if defined(I2C_FLTR_ANOFF) + i2c->FLTR = 0; // analog filter on, digital filter off + #endif + + return 0; +} + +STATIC int i2c_wait_sr1_set(i2c_t *i2c, uint32_t mask) { + uint32_t t0 = HAL_GetTick(); + while (!(i2c->SR1 & mask)) { + if (HAL_GetTick() - t0 >= I2C_POLL_TIMEOUT_MS) { + i2c->CR1 &= ~I2C_CR1_PE; + return -MP_ETIMEDOUT; + } + } + return 0; +} + +STATIC int i2c_wait_stop(i2c_t *i2c) { + uint32_t t0 = HAL_GetTick(); + while (i2c->CR1 & I2C_CR1_STOP) { + if (HAL_GetTick() - t0 >= I2C_POLL_TIMEOUT_MS) { + i2c->CR1 &= ~I2C_CR1_PE; + return -MP_ETIMEDOUT; + } + } + i2c->CR1 &= ~I2C_CR1_PE; + return 0; +} + +// For write: len = 0, 1 or N +// For read: len = 1, 2 or N; stop = true +int i2c_start_addr(i2c_t *i2c, int rd_wrn, uint16_t addr, size_t next_len, bool stop) { + if (!(i2c->CR1 & I2C_CR1_PE) && (i2c->SR2 & I2C_SR2_MSL)) { + // The F4 I2C peripheral can sometimes get into a bad state where it's disabled + // (PE low) but still an active master (MSL high). It seems the best way to get + // out of this is a full reset. + uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); + RCC->APB1RSTR |= RCC_APB1RSTR_I2C1RST << i2c_id; + RCC->APB1RSTR &= ~(RCC_APB1RSTR_I2C1RST << i2c_id); + } + + // It looks like it's possible to terminate the reading by sending a + // START condition instead of STOP condition but we don't support that. + if (rd_wrn) { + if (!stop) { + return -MP_EINVAL; + } + } + + // Repurpose OAR1 to hold stop flag + i2c->OAR1 = stop; + + // Enable peripheral and send START condition + i2c->CR1 |= I2C_CR1_PE; + i2c->CR1 |= I2C_CR1_START; + + // Wait for START to be sent + int ret; + if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_SB))) { + return ret; + } + + // Send the 7-bit address with read/write bit + i2c->DR = addr << 1 | rd_wrn; + + // Wait for address to be sent + if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_AF | I2C_SR1_ADDR))) { + return ret; + } + + // Check if the slave responded or not + if (i2c->SR1 & I2C_SR1_AF) { + // Got a NACK + i2c->CR1 |= I2C_CR1_STOP; + i2c_wait_stop(i2c); // Don't leak errors from this call + return -MP_ENODEV; + } + + if (rd_wrn) { + // For reading, set up ACK/NACK control based on number of bytes to read (at least 1 byte) + if (next_len <= 1) { + // NACK next received byte + i2c->CR1 &= ~I2C_CR1_ACK; + } else if (next_len <= 2) { + // NACK second received byte + i2c->CR1 |= I2C_CR1_POS; + i2c->CR1 &= ~I2C_CR1_ACK; + } else { + // ACK next received byte + i2c->CR1 |= I2C_CR1_ACK; + } + } + + // Read SR2 to clear SR1_ADDR + uint32_t sr2 = i2c->SR2; + (void)sr2; + + return 0; +} + +// next_len = 0 or N (>=2) +int i2c_read(i2c_t *i2c, uint8_t *dest, size_t len, size_t next_len) { + if (len == 0) { + return -MP_EINVAL; + } + if (next_len == 1) { + return -MP_EINVAL; + } + + size_t remain = len + next_len; + if (remain == 1) { + // Special case + i2c->CR1 |= I2C_CR1_STOP; + int ret; + if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_RXNE))) { + return ret; + } + *dest = i2c->DR; + } else { + for (; len; --len) { + remain = len + next_len; + int ret; + if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_BTF))) { + return ret; + } + if (remain == 2) { + // In this case next_len == 0 (it's not allowed to be 1) + i2c->CR1 |= I2C_CR1_STOP; + *dest++ = i2c->DR; + *dest = i2c->DR; + break; + } else if (remain == 3) { + // NACK next received byte + i2c->CR1 &= ~I2C_CR1_ACK; + } + *dest++ = i2c->DR; + } + } + + if (!next_len) { + // We sent a stop above, just wait for it to be finished + return i2c_wait_stop(i2c); + } + + return 0; +} + +// next_len = 0 or N +int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len) { + int ret; + if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_AF | I2C_SR1_TXE))) { + return ret; + } + + // Write out the data + int num_acks = 0; + while (len--) { + i2c->DR = *src++; + if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_AF | I2C_SR1_BTF))) { + return ret; + } + if (i2c->SR1 & I2C_SR1_AF) { + // Slave did not respond to byte so stop sending + break; + } + ++num_acks; + } + + if (!next_len) { + if (i2c->OAR1) { + // Send a STOP and wait for it to finish + i2c->CR1 |= I2C_CR1_STOP; + if ((ret = i2c_wait_stop(i2c))) { + return ret; + } + } + } + + return num_acks; +} + +#elif defined(STM32F7) + int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t freq) { uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); @@ -214,6 +444,10 @@ int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len) { return num_acks; } +#endif + +#if defined(STM32F4) || defined(STM32F7) + int i2c_readfrom(i2c_t *i2c, uint16_t addr, uint8_t *dest, size_t len, bool stop) { int ret; if ((ret = i2c_start_addr(i2c, 1, addr, len, stop))) { @@ -230,6 +464,6 @@ int i2c_writeto(i2c_t *i2c, uint16_t addr, const uint8_t *src, size_t len, bool return i2c_write(i2c, src, len, 0); } -#endif // defined(STM32F7) +#endif #endif // MICROPY_HW_ENABLE_HW_I2C From ce824bb67eb3a6a48460f24f041e6e91f8faa24c Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 14 May 2018 13:20:39 +1000 Subject: [PATCH 643/828] stm32/machine_i2c: Use new F4 hardware I2C driver for machine.I2C class. And remove the old one based on ST code. --- ports/stm32/machine_i2c.c | 405 +++----------------------------------- 1 file changed, 24 insertions(+), 381 deletions(-) diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c index 17d3f3ef47..4cb1dc97d6 100644 --- a/ports/stm32/machine_i2c.c +++ b/ports/stm32/machine_i2c.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2016 Damien P. George + * Copyright (c) 2016-2018 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -37,386 +37,7 @@ STATIC const mp_obj_type_t machine_hard_i2c_type; -#if defined(STM32F4) - -// F4xx specific driver for I2C hardware peripheral -// The hardware-specific I2C code below is based heavily on the code from -// V1.5.2 of the STM32 CUBE F4 HAL. Its copyright notice is given here. -/* -* COPYRIGHT(c) 2016 STMicroelectronics -* -* Redistribution and use in source and binary forms, with or without modification, -* are permitted provided that the following conditions are met: -* 1. Redistributions of source code must retain the above copyright notice, -* this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright notice, -* this list of conditions and the following disclaimer in the documentation -* and/or other materials provided with the distribution. -* 3. Neither the name of STMicroelectronics nor the names of its contributors -* may be used to endorse or promote products derived from this software -* without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -typedef struct _machine_hard_i2c_obj_t { - mp_obj_base_t base; - const pyb_i2c_obj_t *pyb; - uint32_t *timeout; -} machine_hard_i2c_obj_t; - -STATIC uint32_t machine_hard_i2c_timeout[4]; - -STATIC const machine_hard_i2c_obj_t machine_hard_i2c_obj[] = { - {{&machine_hard_i2c_type}, &pyb_i2c_obj[0], &machine_hard_i2c_timeout[0]}, - {{&machine_hard_i2c_type}, &pyb_i2c_obj[1], &machine_hard_i2c_timeout[1]}, - {{&machine_hard_i2c_type}, &pyb_i2c_obj[2], &machine_hard_i2c_timeout[2]}, - {{&machine_hard_i2c_type}, &pyb_i2c_obj[3], &machine_hard_i2c_timeout[3]}, -}; - -STATIC void machine_hard_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "I2C(%u, freq=%u, timeout=%u)", - self - &machine_hard_i2c_obj[0] + 1, - pyb_i2c_get_baudrate(self->pyb->i2c), - *self->timeout); -} - -STATIC void machine_hard_i2c_init(const machine_hard_i2c_obj_t *self, uint32_t freq, uint32_t timeout) { - *self->timeout = timeout; - pyb_i2c_init_freq(self->pyb, freq); -} - -// this function is based on STM code -STATIC bool I2C_IsAcknowledgeFailed(I2C_HandleTypeDef *hi2c) { - if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) { - /* Clear NACKF Flag */ - __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); - return true; - } - return false; -} - -// this function is based on STM code -STATIC bool I2C_WaitOnFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, FlagStatus Status, uint32_t Timeout, uint32_t Tickstart) { - /* Wait until flag is set */ - while ((__HAL_I2C_GET_FLAG(hi2c, Flag) ? SET : RESET) == Status) { - if (Timeout != HAL_MAX_DELAY) { - if ((Timeout == 0U)||((HAL_GetTick() - Tickstart ) > Timeout)) { - return false; - } - } - } - return true; -} - -// this function is based on STM code -STATIC int I2C_WaitOnRXNEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart) { - while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == RESET) { - /* Check if a STOPF is detected */ - if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == SET) { - /* Clear STOP Flag */ - __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF); - return -MP_EBUSY; - } - - /* Check for the Timeout */ - if ((Timeout == 0U) || ((HAL_GetTick()-Tickstart) > Timeout)) { - return -MP_ETIMEDOUT; - } - } - return 0; -} - -// this function is based on STM code -STATIC int send_addr_byte(I2C_HandleTypeDef *hi2c, uint8_t addr_byte, uint32_t Timeout, uint32_t Tickstart) { - /* Generate Start */ - hi2c->Instance->CR1 |= I2C_CR1_START; - - /* Wait until SB flag is set */ - if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart)) { - return -MP_ETIMEDOUT; - } - - /* Send slave address */ - hi2c->Instance->DR = addr_byte; - - /* Wait until ADDR flag is set */ - while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_ADDR) == RESET) { - if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) { - // nack received for addr, release the bus cleanly - hi2c->Instance->CR1 |= I2C_CR1_STOP; - __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); - return -MP_ENODEV; - } - - /* Check for the Timeout */ - if (Timeout != HAL_MAX_DELAY) { - if ((Timeout == 0U)||((HAL_GetTick() - Tickstart ) > Timeout)) { - return -MP_ETIMEDOUT; - } - } - } - - return 0; -} - -// this function is based on STM code -int machine_hard_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop) { - machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t*)self_in; - I2C_HandleTypeDef *hi2c = self->pyb->i2c; - uint32_t Timeout = *self->timeout; - - /* Init tickstart for timeout management*/ - uint32_t tickstart = HAL_GetTick(); - -#if 0 - // TODO: for multi-master, here we could wait for the bus to be free - // we'd need a flag to tell if we were in the middle of a set of transactions - // (ie didn't send a stop bit in the last call) - /* Wait until BUSY flag is reset */ - if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart)) { - return -MP_EBUSY; - } -#endif - - /* Check if the I2C is already enabled */ - if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) { - /* Enable I2C peripheral */ - __HAL_I2C_ENABLE(hi2c); - } - - /* Disable Pos */ - hi2c->Instance->CR1 &= ~I2C_CR1_POS; - - /* Enable Acknowledge */ - hi2c->Instance->CR1 |= I2C_CR1_ACK; - - /* Send Slave Address */ - int ret = send_addr_byte(hi2c, I2C_7BIT_ADD_READ(addr << 1), Timeout, tickstart); - if (ret != 0) { - return ret; - } - - if (len == 0U) { - /* Clear ADDR flag */ - __HAL_I2C_CLEAR_ADDRFLAG(hi2c); - - /* Generate Stop */ - if (stop) { - hi2c->Instance->CR1 |= I2C_CR1_STOP; - } - } else if (len == 1U) { - /* Disable Acknowledge */ - hi2c->Instance->CR1 &= ~I2C_CR1_ACK; - - /* Clear ADDR flag */ - __HAL_I2C_CLEAR_ADDRFLAG(hi2c); - - /* Generate Stop */ - if (stop) { - hi2c->Instance->CR1 |= I2C_CR1_STOP; - } - } else if (len == 2U) { - /* Disable Acknowledge */ - hi2c->Instance->CR1 &= ~I2C_CR1_ACK; - - /* Enable Pos */ - hi2c->Instance->CR1 |= I2C_CR1_POS; - - /* Clear ADDR flag */ - __HAL_I2C_CLEAR_ADDRFLAG(hi2c); - } else { - /* Enable Acknowledge */ - hi2c->Instance->CR1 |= I2C_CR1_ACK; - - /* Clear ADDR flag */ - __HAL_I2C_CLEAR_ADDRFLAG(hi2c); - } - - while (len > 0U) { - if (len <= 3U) { - if (len == 1U) { - /* Wait until RXNE flag is set */ - int ret = I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart); - if (ret != 0) { - return ret; - } - - /* Read data from DR */ - *dest++ = hi2c->Instance->DR; - len--; - } else if (len == 2U) { - /* Wait until BTF flag is set */ - if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart)) { - return -MP_ETIMEDOUT; - } - - /* Generate Stop */ - if (stop) { - hi2c->Instance->CR1 |= I2C_CR1_STOP; - } - - /* Read data from DR */ - *dest++ = hi2c->Instance->DR; - len--; - - /* Read data from DR */ - *dest++ = hi2c->Instance->DR; - len--; - } else { - /* Wait until BTF flag is set */ - if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart)) { - return -MP_ETIMEDOUT; - } - - /* Disable Acknowledge */ - hi2c->Instance->CR1 &= ~I2C_CR1_ACK; - - /* Read data from DR */ - *dest++ = hi2c->Instance->DR; - len--; - - /* Wait until BTF flag is set */ - if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart)) { - return -MP_ETIMEDOUT; - } - - /* Generate Stop */ - if (stop) { - hi2c->Instance->CR1 |= I2C_CR1_STOP; - } - - /* Read data from DR */ - *dest++ = hi2c->Instance->DR; - len--; - - /* Read data from DR */ - *dest++ = hi2c->Instance->DR; - len--; - } - } else { - /* Wait until RXNE flag is set */ - int ret = I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart); - if (ret != 0) { - return ret; - } - - /* Read data from DR */ - *dest++ = hi2c->Instance->DR; - len--; - - if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) { - /* Read data from DR */ - *dest++ = hi2c->Instance->DR; - len--; - } - } - } - - return 0; -} - -// this function is based on STM code -int machine_hard_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop) { - machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t*)self_in; - I2C_HandleTypeDef *hi2c = self->pyb->i2c; - uint32_t Timeout = *self->timeout; - - /* Init tickstart for timeout management*/ - uint32_t tickstart = HAL_GetTick(); - -#if 0 - // TODO: for multi-master, here we could wait for the bus to be free - // we'd need a flag to tell if we were in the middle of a set of transactions - // (ie didn't send a stop bit in the last call) - /* Wait until BUSY flag is reset */ - if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart)) { - return -MP_EBUSY; - } -#endif - - /* Check if the I2C is already enabled */ - if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) { - /* Enable I2C peripheral */ - __HAL_I2C_ENABLE(hi2c); - } - - /* Disable Pos */ - hi2c->Instance->CR1 &= ~I2C_CR1_POS; - - /* Send Slave Address */ - int ret = send_addr_byte(hi2c, I2C_7BIT_ADD_WRITE(addr << 1), Timeout, tickstart); - if (ret != 0) { - return ret; - } - - /* Clear ADDR flag */ - __HAL_I2C_CLEAR_ADDRFLAG(hi2c); - - int num_acks = 0; - - while (len > 0U) { - /* Wait until TXE flag is set */ - while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXE) == RESET) { - /* Check if a NACK is detected */ - if (I2C_IsAcknowledgeFailed(hi2c)) { - goto nack; - } - - /* Check for the Timeout */ - if (Timeout != HAL_MAX_DELAY) { - if ((Timeout == 0U) || ((HAL_GetTick()-tickstart) > Timeout)) { - goto timeout; - } - } - } - - /* Write data to DR */ - hi2c->Instance->DR = *src++; - len--; - - /* Wait until BTF flag is set */ - while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == RESET) { - /* Check if a NACK is detected */ - if (I2C_IsAcknowledgeFailed(hi2c)) { - goto nack; - } - - /* Check for the Timeout */ - if (Timeout != HAL_MAX_DELAY) { - if ((Timeout == 0U) || ((HAL_GetTick()-tickstart) > Timeout)) { - goto timeout; - } - } - } - ++num_acks; - } -nack: - - /* Generate Stop */ - if (stop) { - hi2c->Instance->CR1 |= I2C_CR1_STOP; - } - - return num_acks; - -timeout: - // timeout, release the bus cleanly - hi2c->Instance->CR1 |= I2C_CR1_STOP; - return -MP_ETIMEDOUT; -} - -#elif defined(STM32F7) +#if defined(STM32F4) || defined(STM32F7) typedef struct _machine_hard_i2c_obj_t { mp_obj_base_t base; @@ -450,6 +71,26 @@ STATIC const machine_hard_i2c_obj_t machine_hard_i2c_obj[] = { STATIC void machine_hard_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + + #if defined(STM32F4) + + uint32_t freq = self->i2c->CR2 & 0x3f; + uint32_t ccr = self->i2c->CCR; + if (ccr & 0x8000) { + // Fast mode, assume duty cycle of 16/9 + freq = freq * 40000 / (ccr & 0xfff); + } else { + // Standard mode + freq = freq * 500000 / (ccr & 0xfff); + } + + mp_printf(print, "I2C(%u, scl=%q, sda=%q, freq=%u)", + self - &machine_hard_i2c_obj[0] + 1, + mp_hal_pin_name(self->scl), mp_hal_pin_name(self->sda), + freq); + + #else + uint32_t timingr = self->i2c->TIMINGR; uint32_t presc = timingr >> 28; uint32_t sclh = timingr >> 8 & 0xff; @@ -459,6 +100,8 @@ STATIC void machine_hard_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp self - &machine_hard_i2c_obj[0] + 1, mp_hal_pin_name(self->scl), mp_hal_pin_name(self->sda), freq, timingr); + + #endif } void machine_hard_i2c_init(machine_hard_i2c_obj_t *self, uint32_t freq, uint32_t timeout) { From a0f7b4c678829bf252df58f0153351a44bd95059 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 14 May 2018 13:23:18 +1000 Subject: [PATCH 644/828] stm32/accel: Switch pyb.Accel to use new C-level I2C API. --- ports/stm32/accel.c | 52 ++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/ports/stm32/accel.c b/ports/stm32/accel.c index 488391c703..49674eb2da 100644 --- a/ports/stm32/accel.c +++ b/ports/stm32/accel.c @@ -46,7 +46,7 @@ /// /// Raw values are between -32 and 31. -#define MMA_ADDR (0x98) +#define MMA_ADDR (76) #define MMA_REG_X (0) #define MMA_REG_Y (1) #define MMA_REG_Z (2) @@ -62,15 +62,7 @@ void accel_init(void) { STATIC void accel_start(void) { // 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_DISABLE; - I2CHandle1.Init.OwnAddress1 = PYB_I2C_MASTER_ADDRESS; - I2CHandle1.Init.OwnAddress2 = 0xfe; // unused - pyb_i2c_init(&I2CHandle1); + i2c_init(I2C1, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA, 400000); // turn off AVDD, wait 30ms, turn on AVDD, wait 30ms again mp_hal_pin_low(MICROPY_HW_MMA_AVDD_PIN); // turn off @@ -78,22 +70,21 @@ STATIC void accel_start(void) { mp_hal_pin_high(MICROPY_HW_MMA_AVDD_PIN); // turn on mp_hal_delay_ms(30); - HAL_StatusTypeDef status; - - for (int i = 0; i < 10; i++) { - status = HAL_I2C_IsDeviceReady(&I2CHandle1, MMA_ADDR, 10, 200); - if (status == HAL_OK) { + int ret; + for (int i = 0; i < 4; i++) { + ret = i2c_writeto(I2C1, MMA_ADDR, NULL, 0, true); + if (ret == 0) { break; } } - if (status != HAL_OK) { + if (ret != 0) { mp_raise_msg(&mp_type_OSError, "accelerometer not found"); } // set MMA to active mode - uint8_t data[1] = {1}; // active mode - status = HAL_I2C_Mem_Write(&I2CHandle1, MMA_ADDR, MMA_REG_MODE, I2C_MEMADD_SIZE_8BIT, data, 1, 200); + uint8_t data[2] = {MMA_REG_MODE, 1}; // active mode + i2c_writeto(I2C1, MMA_ADDR, data, 2, true); // wait for MMA to become active mp_hal_delay_ms(30); @@ -135,8 +126,9 @@ STATIC mp_obj_t pyb_accel_make_new(const mp_obj_type_t *type, size_t n_args, siz } STATIC mp_obj_t read_axis(int axis) { - uint8_t data[1]; - HAL_I2C_Mem_Read(&I2CHandle1, MMA_ADDR, axis, I2C_MEMADD_SIZE_8BIT, data, 1, 200); + uint8_t data[1] = { axis }; + i2c_writeto(I2C1, MMA_ADDR, data, 1, false); + i2c_readfrom(I2C1, MMA_ADDR, data, 1, true); return mp_obj_new_int(MMA_AXIS_SIGNED_VALUE(data[0])); } @@ -164,8 +156,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_z_obj, pyb_accel_z); /// \method tilt() /// Get the tilt register. STATIC mp_obj_t pyb_accel_tilt(mp_obj_t self_in) { - uint8_t data[1]; - HAL_I2C_Mem_Read(&I2CHandle1, MMA_ADDR, MMA_REG_TILT, I2C_MEMADD_SIZE_8BIT, data, 1, 200); + uint8_t data[1] = { MMA_REG_TILT }; + i2c_writeto(I2C1, MMA_ADDR, data, 1, false); + i2c_readfrom(I2C1, MMA_ADDR, data, 1, true); return mp_obj_new_int(data[0]); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_tilt_obj, pyb_accel_tilt); @@ -177,8 +170,9 @@ STATIC mp_obj_t pyb_accel_filtered_xyz(mp_obj_t self_in) { memmove(self->buf, self->buf + NUM_AXIS, NUM_AXIS * (FILT_DEPTH - 1) * sizeof(int16_t)); - uint8_t data[NUM_AXIS]; - HAL_I2C_Mem_Read(&I2CHandle1, MMA_ADDR, MMA_REG_X, I2C_MEMADD_SIZE_8BIT, data, NUM_AXIS, 200); + uint8_t data[NUM_AXIS] = { MMA_REG_X }; + i2c_writeto(I2C1, MMA_ADDR, data, 1, false); + i2c_readfrom(I2C1, MMA_ADDR, data, 3, true); mp_obj_t tuple[NUM_AXIS]; for (int i = 0; i < NUM_AXIS; i++) { @@ -195,16 +189,16 @@ STATIC mp_obj_t pyb_accel_filtered_xyz(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_filtered_xyz_obj, pyb_accel_filtered_xyz); STATIC mp_obj_t pyb_accel_read(mp_obj_t self_in, mp_obj_t reg) { - uint8_t data[1]; - HAL_I2C_Mem_Read(&I2CHandle1, MMA_ADDR, mp_obj_get_int(reg), I2C_MEMADD_SIZE_8BIT, data, 1, 200); + uint8_t data[1] = { mp_obj_get_int(reg) }; + i2c_writeto(I2C1, MMA_ADDR, data, 1, false); + i2c_writeto(I2C1, MMA_ADDR, data, 1, true); return mp_obj_new_int(data[0]); } MP_DEFINE_CONST_FUN_OBJ_2(pyb_accel_read_obj, pyb_accel_read); STATIC mp_obj_t pyb_accel_write(mp_obj_t self_in, mp_obj_t reg, mp_obj_t val) { - uint8_t data[1]; - data[0] = mp_obj_get_int(val); - HAL_I2C_Mem_Write(&I2CHandle1, MMA_ADDR, mp_obj_get_int(reg), I2C_MEMADD_SIZE_8BIT, data, 1, 200); + uint8_t data[2] = { mp_obj_get_int(reg), mp_obj_get_int(val) }; + i2c_writeto(I2C1, MMA_ADDR, data, 2, true); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_3(pyb_accel_write_obj, pyb_accel_write); From 92c5e2708d48a114f209a2299babb2c6de78ce22 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 14 May 2018 13:49:22 +1000 Subject: [PATCH 645/828] stm32/modpyb: Introduce MICROPY_PY_PYB_LEGACY config option for pyb mod. This is enabled by default. When it is disabled all legacy functions and classes in the pyb module are excluded from the build. --- ports/stm32/modpyb.c | 14 ++++++++++++++ ports/stm32/mpconfigboard_common.h | 5 +++++ 2 files changed, 19 insertions(+) diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c index 59c6ba67cb..3438b12e8e 100644 --- a/ports/stm32/modpyb.c +++ b/ports/stm32/modpyb.c @@ -69,6 +69,8 @@ STATIC mp_obj_t pyb_fault_debug(mp_obj_t value) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_fault_debug_obj, pyb_fault_debug); +#if MICROPY_PY_PYB_LEGACY + /// \function elapsed_millis(start) /// Returns the number of milliseconds which have elapsed since `start`. /// @@ -103,6 +105,8 @@ STATIC mp_obj_t pyb_elapsed_micros(mp_obj_t start) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_elapsed_micros_obj, pyb_elapsed_micros); +#endif + MP_DECLARE_CONST_FUN_OBJ_KW(pyb_main_obj); // defined in main.c // Get or set the UART object that the REPL is repeated on. @@ -136,11 +140,13 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_fault_debug), MP_ROM_PTR(&pyb_fault_debug_obj) }, + #if MICROPY_PY_PYB_LEGACY { MP_ROM_QSTR(MP_QSTR_bootloader), MP_ROM_PTR(&machine_bootloader_obj) }, { MP_ROM_QSTR(MP_QSTR_hard_reset), MP_ROM_PTR(&machine_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&machine_info_obj) }, { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) }, { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_repl_info), MP_ROM_PTR(&pyb_set_repl_info_obj) }, { MP_ROM_QSTR(MP_QSTR_wfi), MP_ROM_PTR(&pyb_wfi_obj) }, @@ -150,8 +156,10 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_irq_stats), MP_ROM_PTR(&pyb_irq_stats_obj) }, #endif + #if MICROPY_PY_PYB_LEGACY { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&machine_sleep_obj) }, { MP_ROM_QSTR(MP_QSTR_standby), MP_ROM_PTR(&machine_deepsleep_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_main), MP_ROM_PTR(&pyb_main_obj) }, { MP_ROM_QSTR(MP_QSTR_repl_uart), MP_ROM_PTR(&pyb_repl_uart_obj) }, @@ -161,11 +169,14 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_hid_keyboard), MP_ROM_PTR(&pyb_usb_hid_keyboard_obj) }, { MP_ROM_QSTR(MP_QSTR_USB_VCP), MP_ROM_PTR(&pyb_usb_vcp_type) }, { MP_ROM_QSTR(MP_QSTR_USB_HID), MP_ROM_PTR(&pyb_usb_hid_type) }, + #if MICROPY_PY_PYB_LEGACY // these 2 are deprecated; use USB_VCP.isconnected and USB_HID.send instead { MP_ROM_QSTR(MP_QSTR_have_cdc), MP_ROM_PTR(&pyb_have_cdc_obj) }, { MP_ROM_QSTR(MP_QSTR_hid), MP_ROM_PTR(&pyb_hid_send_report_obj) }, #endif + #endif + #if MICROPY_PY_PYB_LEGACY { MP_ROM_QSTR(MP_QSTR_millis), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, { MP_ROM_QSTR(MP_QSTR_elapsed_millis), MP_ROM_PTR(&pyb_elapsed_millis_obj) }, { MP_ROM_QSTR(MP_QSTR_micros), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, @@ -174,6 +185,7 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_udelay), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&mod_os_sync_obj) }, { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, + #endif // This function is not intended to be public and may be moved elsewhere { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) }, @@ -206,7 +218,9 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { #endif #if MICROPY_HW_HAS_SDCARD + #if MICROPY_PY_PYB_LEGACY { MP_ROM_QSTR(MP_QSTR_SD), MP_ROM_PTR(&pyb_sdcard_obj) }, // now obsolete + #endif { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&pyb_sdcard_type) }, #endif diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 2ed8609e74..a33b8d042d 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -37,6 +37,11 @@ #define MICROPY_PY_STM (1) #endif +// Whether to include legacy functions and classes in the pyb module +#ifndef MICROPY_PY_PYB_LEGACY +#define MICROPY_PY_PYB_LEGACY (1) +#endif + // Whether to enable storage on the internal flash of the MCU #ifndef MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE #define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (1) From 88c26a48b4a3c8850ff2677b2f0ce8c90ba8e660 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 14 May 2018 13:53:46 +1000 Subject: [PATCH 646/828] stm32/pyb_i2c: Put pyb.I2C under MICROPY_PY_PYB_LEGACY setting. When disabled, the pyb.I2C class saves around 8k of code space and 172 bytes of RAM. The same functionality is now available in machine.I2C (for F4 and F7 MCUs). It is still enabled by default. --- ports/stm32/main.c | 2 +- ports/stm32/modpyb.c | 2 +- ports/stm32/pyb_i2c.c | 4 ++-- ports/stm32/stm32_it.c | 4 ++++ 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 4553a07e28..460a19ccb1 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -505,7 +505,7 @@ void stm32_main(uint32_t reset_mode) { rtc_init_start(false); #endif spi_init0(); - #if MICROPY_HW_ENABLE_HW_I2C + #if MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C i2c_init0(); #endif #if MICROPY_HW_HAS_SDCARD diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c index 3438b12e8e..6357aca946 100644 --- a/ports/stm32/modpyb.c +++ b/ports/stm32/modpyb.c @@ -227,7 +227,7 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { #if defined(MICROPY_HW_LED1) { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pyb_led_type) }, #endif - #if MICROPY_HW_ENABLE_HW_I2C + #if MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&pyb_i2c_type) }, #endif { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&pyb_spi_type) }, diff --git a/ports/stm32/pyb_i2c.c b/ports/stm32/pyb_i2c.c index db09f688bf..33aaa48cbb 100644 --- a/ports/stm32/pyb_i2c.c +++ b/ports/stm32/pyb_i2c.c @@ -35,7 +35,7 @@ #include "dma.h" #include "i2c.h" -#if MICROPY_HW_ENABLE_HW_I2C +#if MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C /// \moduleref pyb /// \class I2C - a two-wire serial protocol @@ -1065,4 +1065,4 @@ const mp_obj_type_t pyb_i2c_type = { .locals_dict = (mp_obj_dict_t*)&pyb_i2c_locals_dict, }; -#endif // MICROPY_HW_ENABLE_HW_I2C +#endif // MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index db812958fb..a77802bfa4 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -776,6 +776,8 @@ void CAN2_SCE_IRQHandler(void) { } #endif +#if MICROPY_PY_PYB_LEGACY + #if defined(MICROPY_HW_I2C1_SCL) void I2C1_EV_IRQHandler(void) { IRQ_ENTER(I2C1_EV_IRQn); @@ -831,3 +833,5 @@ void I2C4_ER_IRQHandler(void) { IRQ_EXIT(I2C4_ER_IRQn); } #endif // defined(MICROPY_HW_I2C4_SCL) + +#endif // MICROPY_PY_PYB_LEGACY From fb25c810629114092e173da578348410a21192bc Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 14 May 2018 14:01:50 +1000 Subject: [PATCH 647/828] stm32/modpyb: Remove unused includes and clean up comments. The documentation (including the examples) for elapsed_millis and elapsed_micros can be found in docs/library/pyb.rst so doesn't need to be written in full in the source code. --- ports/stm32/modpyb.c | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c index 6357aca946..5afbbc4842 100644 --- a/ports/stm32/modpyb.c +++ b/ports/stm32/modpyb.c @@ -28,19 +28,12 @@ #include #include "py/runtime.h" -#include "py/gc.h" -#include "py/builtin.h" #include "py/mphal.h" #include "lib/utils/pyexec.h" -#include "lib/oofatfs/ff.h" -#include "lib/oofatfs/diskio.h" #include "drivers/dht/dht.h" -#include "gccollect.h" #include "stm32_it.h" #include "irq.h" -#include "systick.h" #include "led.h" -#include "pin.h" #include "timer.h" #include "extint.h" #include "usrsw.h" @@ -71,16 +64,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_fault_debug_obj, pyb_fault_debug); #if MICROPY_PY_PYB_LEGACY -/// \function elapsed_millis(start) -/// Returns the number of milliseconds which have elapsed since `start`. -/// -/// This function takes care of counter wrap, and always returns a positive -/// number. This means it can be used to measure periods upto about 12.4 days. -/// -/// Example: -/// start = pyb.millis() -/// while pyb.elapsed_millis(start) < 1000: -/// # Perform some operation +// Returns the number of milliseconds which have elapsed since `start`. +// This function takes care of counter wrap and always returns a positive number. STATIC mp_obj_t pyb_elapsed_millis(mp_obj_t start) { uint32_t startMillis = mp_obj_get_int(start); uint32_t currMillis = mp_hal_ticks_ms(); @@ -88,16 +73,8 @@ STATIC mp_obj_t pyb_elapsed_millis(mp_obj_t start) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_elapsed_millis_obj, pyb_elapsed_millis); -/// \function elapsed_micros(start) -/// Returns the number of microseconds which have elapsed since `start`. -/// -/// This function takes care of counter wrap, and always returns a positive -/// number. This means it can be used to measure periods upto about 17.8 minutes. -/// -/// Example: -/// start = pyb.micros() -/// while pyb.elapsed_micros(start) < 1000: -/// # Perform some operation +// Returns the number of microseconds which have elapsed since `start`. +// This function takes care of counter wrap and always returns a positive number. STATIC mp_obj_t pyb_elapsed_micros(mp_obj_t start) { uint32_t startMicros = mp_obj_get_int(start); uint32_t currMicros = mp_hal_ticks_us(); From ed32284b70d83c9ffd223070d8eb9cd05afc8465 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 14 May 2018 15:24:44 +1000 Subject: [PATCH 648/828] stm32/usb: Use usbd_cdc_itf_t pointer directly in USB_VCP class. --- ports/stm32/usb.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 3448c65ddc..1e8052d2ff 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -354,10 +354,10 @@ MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_mode_obj, 0, pyb_usb_mode); typedef struct _pyb_usb_vcp_obj_t { mp_obj_base_t base; - usb_device_t *usb_dev; + usbd_cdc_itf_t *cdc_itf; } pyb_usb_vcp_obj_t; -STATIC const pyb_usb_vcp_obj_t pyb_usb_vcp_obj = {{&pyb_usb_vcp_type}, &usb_device}; +STATIC const pyb_usb_vcp_obj_t pyb_usb_vcp_obj = {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc_itf}; STATIC void pyb_usb_vcp_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { mp_print_str(print, "USB_VCP()"); @@ -383,7 +383,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_usb_vcp_setinterrupt_obj, pyb_usb_vcp_setin STATIC mp_obj_t pyb_usb_vcp_isconnected(mp_obj_t self_in) { pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_bool(usbd_cdc_is_connected(&self->usb_dev->usbd_cdc_itf)); + return mp_obj_new_bool(usbd_cdc_is_connected(self->cdc_itf)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_usb_vcp_isconnected_obj, pyb_usb_vcp_isconnected); @@ -397,7 +397,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(pyb_have_cdc_obj, pyb_have_cdc); /// Return `True` if any characters waiting, else `False`. STATIC mp_obj_t pyb_usb_vcp_any(mp_obj_t self_in) { pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (usbd_cdc_rx_num(&self->usb_dev->usbd_cdc_itf) > 0) { + if (usbd_cdc_rx_num(self->cdc_itf) > 0) { return mp_const_true; } else { return mp_const_false; @@ -430,7 +430,7 @@ STATIC mp_obj_t pyb_usb_vcp_send(size_t n_args, const mp_obj_t *args, mp_map_t * pyb_buf_get_for_send(vals[0].u_obj, &bufinfo, data); // send the data - int ret = usbd_cdc_tx(&self->usb_dev->usbd_cdc_itf, bufinfo.buf, bufinfo.len, vals[1].u_int); + int ret = usbd_cdc_tx(self->cdc_itf, bufinfo.buf, bufinfo.len, vals[1].u_int); return mp_obj_new_int(ret); } @@ -457,7 +457,7 @@ STATIC mp_obj_t pyb_usb_vcp_recv(size_t n_args, const mp_obj_t *args, mp_map_t * mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &vstr); // receive the data - int ret = usbd_cdc_rx(&self->usb_dev->usbd_cdc_itf, (uint8_t*)vstr.buf, vstr.len, vals[1].u_int); + int ret = usbd_cdc_rx(self->cdc_itf, (uint8_t*)vstr.buf, vstr.len, vals[1].u_int); // return the received data if (o_ret != MP_OBJ_NULL) { @@ -495,7 +495,7 @@ STATIC MP_DEFINE_CONST_DICT(pyb_usb_vcp_locals_dict, pyb_usb_vcp_locals_dict_tab STATIC mp_uint_t pyb_usb_vcp_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in); - int ret = usbd_cdc_rx(&self->usb_dev->usbd_cdc_itf, (byte*)buf, size, 0); + int ret = usbd_cdc_rx(self->cdc_itf, (byte*)buf, size, 0); if (ret == 0) { // return EAGAIN error to indicate non-blocking *errcode = MP_EAGAIN; @@ -506,7 +506,7 @@ STATIC mp_uint_t pyb_usb_vcp_read(mp_obj_t self_in, void *buf, mp_uint_t size, i STATIC mp_uint_t pyb_usb_vcp_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in); - int ret = usbd_cdc_tx(&self->usb_dev->usbd_cdc_itf, (const byte*)buf, size, 0); + int ret = usbd_cdc_tx(self->cdc_itf, (const byte*)buf, size, 0); if (ret == 0) { // return EAGAIN error to indicate non-blocking *errcode = MP_EAGAIN; @@ -521,10 +521,10 @@ STATIC mp_uint_t pyb_usb_vcp_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_ if (request == MP_STREAM_POLL) { mp_uint_t flags = arg; ret = 0; - if ((flags & MP_STREAM_POLL_RD) && usbd_cdc_rx_num(&self->usb_dev->usbd_cdc_itf) > 0) { + if ((flags & MP_STREAM_POLL_RD) && usbd_cdc_rx_num(self->cdc_itf) > 0) { ret |= MP_STREAM_POLL_RD; } - if ((flags & MP_STREAM_POLL_WR) && usbd_cdc_tx_half_empty(&self->usb_dev->usbd_cdc_itf)) { + if ((flags & MP_STREAM_POLL_WR) && usbd_cdc_tx_half_empty(self->cdc_itf)) { ret |= MP_STREAM_POLL_WR; } } else { From bf08a99ccdbe79bb13a1f28c48e31da8dbaaf6f6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 14 May 2018 16:15:58 +1000 Subject: [PATCH 649/828] stm32/usb: Combine CDC lower-layer and interface state into one struct. --- ports/stm32/usb.c | 14 +++---- ports/stm32/usbd_cdc_interface.c | 19 +++++---- ports/stm32/usbd_cdc_interface.h | 2 +- .../stm32/usbdev/class/inc/usbd_cdc_msc_hid.h | 25 ++++++------ .../stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 40 ++++++++++--------- 5 files changed, 53 insertions(+), 47 deletions(-) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 1e8052d2ff..e86f69ac55 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -119,12 +119,6 @@ bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_H if (!usb_dev->enabled) { // only init USB once in the device's power-lifetime - // configure the VID, PID and the USBD mode (interfaces it will expose) - USBD_SetVIDPIDRelease(&usb_dev->usbd_cdc_msc_hid_state, vid, pid, 0x0200, mode == USBD_MODE_CDC); - if (USBD_SelectMode(&usb_dev->usbd_cdc_msc_hid_state, mode, hid_info) != 0) { - return false; - } - // set up the USBD state USBD_HandleTypeDef *usbd = &usb_dev->hUSBDDevice; usbd->id = MICROPY_HW_USB_MAIN_DEV; @@ -132,10 +126,16 @@ bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_H usbd->pDesc = (USBD_DescriptorsTypeDef*)&USBD_Descriptors; usbd->pClass = &USBD_CDC_MSC_HID; usb_dev->usbd_cdc_msc_hid_state.pdev = usbd; - usb_dev->usbd_cdc_msc_hid_state.cdc = &usb_dev->usbd_cdc_itf; + usb_dev->usbd_cdc_msc_hid_state.cdc = &usb_dev->usbd_cdc_itf.base; usb_dev->usbd_cdc_msc_hid_state.hid = &usb_dev->usbd_hid_itf; usbd->pClassData = &usb_dev->usbd_cdc_msc_hid_state; + // configure the VID, PID and the USBD mode (interfaces it will expose) + USBD_SetVIDPIDRelease(&usb_dev->usbd_cdc_msc_hid_state, vid, pid, 0x0200, mode == USBD_MODE_CDC); + if (USBD_SelectMode(&usb_dev->usbd_cdc_msc_hid_state, mode, hid_info) != 0) { + return false; + } + switch (pyb_usb_storage_medium) { #if MICROPY_HW_HAS_SDCARD case PYB_USB_STORAGE_MEDIUM_SDCARD: diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c index 23085510cc..a987646e7a 100644 --- a/ports/stm32/usbd_cdc_interface.c +++ b/ports/stm32/usbd_cdc_interface.c @@ -56,9 +56,8 @@ #define CDC_SET_CONTROL_LINE_STATE 0x22 #define CDC_SEND_BREAK 0x23 -uint8_t *usbd_cdc_init(usbd_cdc_itf_t *cdc, usbd_cdc_msc_hid_state_t *usbd) { - // Link the parent state - cdc->usbd = usbd; +uint8_t *usbd_cdc_init(usbd_cdc_state_t *cdc_in) { + usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)cdc_in; // Reset all the CDC state // Note: we don't reset tx_buf_ptr_in in order to allow the output buffer to @@ -80,7 +79,9 @@ uint8_t *usbd_cdc_init(usbd_cdc_itf_t *cdc, usbd_cdc_msc_hid_state_t *usbd) { // pbuf: buffer containing command data (request parameters) // length: number of data to be sent (in bytes) // Returns USBD_OK if all operations are OK else USBD_FAIL -int8_t usbd_cdc_control(usbd_cdc_itf_t *cdc, uint8_t cmd, uint8_t* pbuf, uint16_t length) { +int8_t usbd_cdc_control(usbd_cdc_state_t *cdc_in, uint8_t cmd, uint8_t* pbuf, uint16_t length) { + usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)cdc_in; + switch (cmd) { case CDC_SEND_ENCAPSULATED_COMMAND: /* Add your code here */ @@ -144,7 +145,7 @@ int8_t usbd_cdc_control(usbd_cdc_itf_t *cdc, uint8_t cmd, uint8_t* pbuf, uint16_ // needed (reducing latency), and often enough (increasing bandwidth). void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { usbd_cdc_msc_hid_state_t *usbd = ((USBD_HandleTypeDef*)hpcd->pData)->pClassData; - usbd_cdc_itf_t *cdc = usbd->cdc; + usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)usbd->cdc; if (cdc == NULL || !cdc->dev_is_connected) { // CDC device is not connected to a host, so we are unable to send any data @@ -185,7 +186,7 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { buffptr = cdc->tx_buf_ptr_out_shadow; - if (USBD_CDC_TransmitPacket(cdc->usbd, buffsize, &cdc->tx_buf[buffptr]) == USBD_OK) { + if (USBD_CDC_TransmitPacket(cdc->base.usbd, buffsize, &cdc->tx_buf[buffptr]) == USBD_OK) { cdc->tx_buf_ptr_out_shadow += buffsize; if (cdc->tx_buf_ptr_out_shadow == USBD_CDC_TX_DATA_SIZE) { cdc->tx_buf_ptr_out_shadow = 0; @@ -206,7 +207,9 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { // Data received over USB OUT endpoint is processed here. // len: number of bytes received into the buffer we passed to USBD_CDC_ReceivePacket // Returns USBD_OK if all operations are OK else USBD_FAIL -int8_t usbd_cdc_receive(usbd_cdc_itf_t *cdc, size_t len) { +int8_t usbd_cdc_receive(usbd_cdc_state_t *cdc_in, size_t len) { + usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)cdc_in; + // copy the incoming data into the circular buffer for (const uint8_t *src = cdc->rx_packet_buf, *top = cdc->rx_packet_buf + len; src < top; ++src) { if (mp_interrupt_char != -1 && *src == mp_interrupt_char) { @@ -223,7 +226,7 @@ int8_t usbd_cdc_receive(usbd_cdc_itf_t *cdc, size_t len) { } // initiate next USB packet transfer - USBD_CDC_ReceivePacket(cdc->usbd, cdc->rx_packet_buf); + USBD_CDC_ReceivePacket(cdc->base.usbd, cdc->rx_packet_buf); return USBD_OK; } diff --git a/ports/stm32/usbd_cdc_interface.h b/ports/stm32/usbd_cdc_interface.h index 36a89e7dbc..bfcdfaf333 100644 --- a/ports/stm32/usbd_cdc_interface.h +++ b/ports/stm32/usbd_cdc_interface.h @@ -35,7 +35,7 @@ #define USBD_CDC_TX_DATA_SIZE (1024) // I think this can be any value (was 2048) typedef struct _usbd_cdc_itf_t { - usbd_cdc_msc_hid_state_t *usbd; // the parent USB device + usbd_cdc_state_t base; // state for the base CDC layer uint8_t rx_packet_buf[CDC_DATA_MAX_PACKET_SIZE]; // received data from USB OUT endpoint is stored in this buffer uint8_t rx_user_buf[USBD_CDC_RX_DATA_SIZE]; // received data is buffered here until the user reads it diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h index 1ff22ba904..43a494ebd9 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -44,12 +44,16 @@ #define CDC_OUT_EP (0x03) #define CDC_CMD_EP (0x82) +struct _usbd_cdc_msc_hid_state_t; + typedef struct { - uint32_t data[CDC_DATA_MAX_PACKET_SIZE / 4]; // Force 32bits alignment - uint8_t CmdOpCode; - uint8_t CmdLength; - volatile uint32_t TxState; -} USBD_CDC_HandleTypeDef; + struct _usbd_cdc_msc_hid_state_t *usbd; // The parent USB device + uint32_t ctl_packet_buf[CDC_DATA_MAX_PACKET_SIZE / 4]; // Force 32-bit alignment + uint8_t iface_num; + uint8_t cur_request; + uint8_t cur_length; + volatile uint8_t tx_in_progress; +} usbd_cdc_state_t; typedef struct _USBD_STORAGE { int8_t (* Init) (uint8_t lun); @@ -104,7 +108,6 @@ typedef struct _usbd_cdc_msc_hid_state_t { USBD_HandleTypeDef *pdev; uint8_t usbd_mode; - uint8_t cdc_iface_num; uint8_t hid_in_ep; uint8_t hid_out_ep; uint8_t hid_iface_num; @@ -112,7 +115,6 @@ typedef struct _usbd_cdc_msc_hid_state_t { uint8_t *hid_desc; const uint8_t *hid_report_desc; - USBD_CDC_HandleTypeDef CDC_ClassData; USBD_MSC_BOT_HandleTypeDef MSC_BOT_ClassData; USBD_HID_HandleTypeDef HID_ClassData; @@ -121,7 +123,7 @@ typedef struct _usbd_cdc_msc_hid_state_t { __ALIGN_BEGIN uint8_t usbd_str_desc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END; __ALIGN_BEGIN uint8_t usbd_config_desc[MAX_TEMPLATE_CONFIG_DESC_SIZE] __ALIGN_END; - void *cdc; + usbd_cdc_state_t *cdc; void *hid; } usbd_cdc_msc_hid_state_t; @@ -178,10 +180,9 @@ uint8_t USBD_HID_SetNAK(usbd_cdc_msc_hid_state_t *usbd); uint8_t USBD_HID_ClearNAK(usbd_cdc_msc_hid_state_t *usbd); // These are provided externally to implement the CDC interface -struct _usbd_cdc_itf_t; -uint8_t *usbd_cdc_init(struct _usbd_cdc_itf_t *cdc, usbd_cdc_msc_hid_state_t *usbd); -int8_t usbd_cdc_control(struct _usbd_cdc_itf_t *cdc, uint8_t cmd, uint8_t* pbuf, uint16_t length); -int8_t usbd_cdc_receive(struct _usbd_cdc_itf_t *cdc, size_t len); +uint8_t *usbd_cdc_init(usbd_cdc_state_t *cdc); +int8_t usbd_cdc_control(usbd_cdc_state_t *cdc, uint8_t cmd, uint8_t* pbuf, uint16_t length); +int8_t usbd_cdc_receive(usbd_cdc_state_t *cdc, size_t len); // These are provided externally to implement the HID interface struct _usbd_hid_itf_t; diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c index 2e1df0cb76..7944ae7778 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -617,13 +617,13 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode case USBD_MODE_CDC_MSC: usbd->usbd_config_desc_size = sizeof(cdc_msc_template_config_desc); memcpy(usbd->usbd_config_desc, cdc_msc_template_config_desc, sizeof(cdc_msc_template_config_desc)); - usbd->cdc_iface_num = CDC_IFACE_NUM_WITH_MSC; + usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_MSC; break; case USBD_MODE_CDC_HID: usbd->usbd_config_desc_size = sizeof(cdc_hid_template_config_desc); memcpy(usbd->usbd_config_desc, cdc_hid_template_config_desc, sizeof(cdc_hid_template_config_desc)); - usbd->cdc_iface_num = CDC_IFACE_NUM_WITH_HID; + usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_HID; usbd->hid_in_ep = HID_IN_EP_WITH_CDC; usbd->hid_out_ep = HID_OUT_EP_WITH_CDC; usbd->hid_iface_num = HID_IFACE_NUM_WITH_CDC; @@ -633,7 +633,7 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode case USBD_MODE_CDC: usbd->usbd_config_desc_size = sizeof(cdc_template_config_desc); memcpy(usbd->usbd_config_desc, cdc_template_config_desc, sizeof(cdc_template_config_desc)); - usbd->cdc_iface_num = CDC_IFACE_NUM_ALONE; + usbd->cdc->iface_num = CDC_IFACE_NUM_ALONE; break; /* @@ -701,11 +701,13 @@ static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE); - // Init physical Interface components - uint8_t *buf = usbd_cdc_init(usbd->cdc, usbd); - // Init Xfer states - usbd->CDC_ClassData.TxState = 0; + usbd->cdc->usbd = usbd; + usbd->cdc->cur_request = 0xff; + usbd->cdc->tx_in_progress = 0; + + // Init physical Interface components + uint8_t *buf = usbd_cdc_init(usbd->cdc); // Prepare Out endpoint to receive next packet USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, buf, mp); @@ -826,7 +828,7 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp switch (req->bmRequest & USB_REQ_RECIPIENT_MASK) { case USB_REQ_RECIPIENT_INTERFACE: { uint16_t iface = req->wIndex; - if ((mode & USBD_MODE_CDC) && iface == usbd->cdc_iface_num) { + if ((mode & USBD_MODE_CDC) && iface == usbd->cdc->iface_num) { recipient = USBD_MODE_CDC; } else if ((mode & USBD_MODE_MSC) && iface == MSC_IFACE_NUM_WITH_CDC) { recipient = USBD_MODE_MSC; @@ -862,13 +864,13 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp if (req->wLength) { if (req->bmRequest & 0x80) { // device-to-host request - usbd_cdc_control(usbd->cdc, req->bRequest, (uint8_t*)usbd->CDC_ClassData.data, req->wLength); - USBD_CtlSendData(pdev, (uint8_t*)usbd->CDC_ClassData.data, req->wLength); + usbd_cdc_control(usbd->cdc, req->bRequest, (uint8_t*)usbd->cdc->ctl_packet_buf, req->wLength); + USBD_CtlSendData(pdev, (uint8_t*)usbd->cdc->ctl_packet_buf, req->wLength); } else { // host-to-device request - usbd->CDC_ClassData.CmdOpCode = req->bRequest; - usbd->CDC_ClassData.CmdLength = req->wLength; - USBD_CtlPrepareRx(pdev, (uint8_t*)usbd->CDC_ClassData.data, req->wLength); + usbd->cdc->cur_request = req->bRequest; + usbd->cdc->cur_length = req->wLength; + USBD_CtlPrepareRx(pdev, (uint8_t*)usbd->cdc->ctl_packet_buf, req->wLength); } } else { // Not a Data request @@ -991,9 +993,9 @@ static uint8_t EP0_TxSent(USBD_HandleTypeDef *pdev) { static uint8_t USBD_CDC_MSC_HID_EP0_RxReady(USBD_HandleTypeDef *pdev) { usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; - if (usbd->cdc != NULL && usbd->CDC_ClassData.CmdOpCode != 0xff) { - usbd_cdc_control(usbd->cdc, usbd->CDC_ClassData.CmdOpCode, (uint8_t*)usbd->CDC_ClassData.data, usbd->CDC_ClassData.CmdLength); - usbd->CDC_ClassData.CmdOpCode = 0xff; + if (usbd->cdc != NULL && usbd->cdc->cur_request != 0xff) { + usbd_cdc_control(usbd->cdc, usbd->cdc->cur_request, (uint8_t*)usbd->cdc->ctl_packet_buf, usbd->cdc->cur_length); + usbd->cdc->cur_request = 0xff; } return USBD_OK; @@ -1002,7 +1004,7 @@ static uint8_t USBD_CDC_MSC_HID_EP0_RxReady(USBD_HandleTypeDef *pdev) { static uint8_t USBD_CDC_MSC_HID_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) { usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; if ((usbd->usbd_mode & USBD_MODE_CDC) && (epnum == (CDC_IN_EP & 0x7f) || epnum == (CDC_CMD_EP & 0x7f))) { - usbd->CDC_ClassData.TxState = 0; + usbd->cdc->tx_in_progress = 0; return USBD_OK; } else if ((usbd->usbd_mode & USBD_MODE_MSC) && epnum == (MSC_IN_EP & 0x7f)) { MSC_BOT_DataIn(pdev, epnum); @@ -1105,12 +1107,12 @@ uint8_t *USBD_CDC_MSC_HID_GetDeviceQualifierDescriptor(USBD_HandleTypeDef *pdev, // data received on non-control OUT endpoint uint8_t USBD_CDC_TransmitPacket(usbd_cdc_msc_hid_state_t *usbd, size_t len, const uint8_t *buf) { - if (usbd->CDC_ClassData.TxState == 0) { + if (usbd->cdc->tx_in_progress == 0) { // transmit next packet USBD_LL_Transmit(usbd->pdev, CDC_IN_EP, (uint8_t*)buf, len); // Tx transfer in progress - usbd->CDC_ClassData.TxState = 1; + usbd->cdc->tx_in_progress = 1; return USBD_OK; } else { return USBD_BUSY; From ed92d623269a70051c59fae5e909b97779dac54e Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 14 May 2018 16:34:31 +1000 Subject: [PATCH 650/828] stm32/usb: Combine HID lower-layer and interface state into one struct. --- ports/stm32/usb.c | 2 +- ports/stm32/usbd_hid_interface.c | 15 ++-- ports/stm32/usbd_hid_interface.h | 2 +- .../stm32/usbdev/class/inc/usbd_cdc_msc_hid.h | 29 ++++--- .../stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 84 +++++++++---------- 5 files changed, 65 insertions(+), 67 deletions(-) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index e86f69ac55..e253cf0118 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -127,7 +127,7 @@ bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_H usbd->pClass = &USBD_CDC_MSC_HID; usb_dev->usbd_cdc_msc_hid_state.pdev = usbd; usb_dev->usbd_cdc_msc_hid_state.cdc = &usb_dev->usbd_cdc_itf.base; - usb_dev->usbd_cdc_msc_hid_state.hid = &usb_dev->usbd_hid_itf; + usb_dev->usbd_cdc_msc_hid_state.hid = &usb_dev->usbd_hid_itf.base; usbd->pClassData = &usb_dev->usbd_cdc_msc_hid_state; // configure the VID, PID and the USBD mode (interfaces it will expose) diff --git a/ports/stm32/usbd_hid_interface.c b/ports/stm32/usbd_hid_interface.c index 9ab5986b66..d8c160fe7b 100644 --- a/ports/stm32/usbd_hid_interface.c +++ b/ports/stm32/usbd_hid_interface.c @@ -42,8 +42,9 @@ #include "irq.h" #include "usb.h" -uint8_t *usbd_hid_init(usbd_hid_itf_t *hid, usbd_cdc_msc_hid_state_t *usbd) { - hid->usbd = usbd; +uint8_t *usbd_hid_init(usbd_hid_state_t *hid_in) { + usbd_hid_itf_t *hid = (usbd_hid_itf_t*)hid_in; + hid->current_read_buffer = 0; hid->last_read_len = 0; hid->current_write_buffer = 0; @@ -55,13 +56,15 @@ uint8_t *usbd_hid_init(usbd_hid_itf_t *hid, usbd_cdc_msc_hid_state_t *usbd) { // Data received over USB OUT endpoint is processed here. // len: number of bytes received into the buffer we passed to USBD_HID_ReceivePacket // Returns USBD_OK if all operations are OK else USBD_FAIL -int8_t usbd_hid_receive(usbd_hid_itf_t *hid, size_t len) { +int8_t usbd_hid_receive(usbd_hid_state_t *hid_in, size_t len) { + usbd_hid_itf_t *hid = (usbd_hid_itf_t*)hid_in; + hid->current_write_buffer = !hid->current_write_buffer; hid->last_read_len = len; // initiate next USB packet transfer, to append to existing data in buffer - USBD_HID_ReceivePacket(hid->usbd, hid->buffer[hid->current_write_buffer]); + USBD_HID_ReceivePacket(hid->base.usbd, hid->buffer[hid->current_write_buffer]); // Set NAK to indicate we need to process read buffer - USBD_HID_SetNAK(hid->usbd); + USBD_HID_SetNAK(hid->base.usbd); return USBD_OK; } @@ -99,7 +102,7 @@ int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout) hid->current_read_buffer = !hid->current_read_buffer; // Clear NAK to indicate we are ready to read more data - USBD_HID_ClearNAK(hid->usbd); + USBD_HID_ClearNAK(hid->base.usbd); // Success, return number of bytes read return read_len; diff --git a/ports/stm32/usbd_hid_interface.h b/ports/stm32/usbd_hid_interface.h index d9adf8a5f3..777fa93403 100644 --- a/ports/stm32/usbd_hid_interface.h +++ b/ports/stm32/usbd_hid_interface.h @@ -7,7 +7,7 @@ #include "usbd_cdc_msc_hid.h" typedef struct _usbd_hid_itf_t { - usbd_cdc_msc_hid_state_t *usbd; // the parent USB device + usbd_hid_state_t base; // state for the base HID layer uint8_t buffer[2][HID_DATA_FS_MAX_PACKET_SIZE]; // pair of buffers to read individual packets into int8_t current_read_buffer; // which buffer to read from diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h index 43a494ebd9..18c2c56c3c 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -98,25 +98,25 @@ typedef enum { } HID_StateTypeDef; typedef struct { - uint32_t Protocol; - uint32_t IdleState; - uint32_t AltSetting; - HID_StateTypeDef state; -} USBD_HID_HandleTypeDef; + struct _usbd_cdc_msc_hid_state_t *usbd; // The parent USB device + uint8_t iface_num; + uint8_t in_ep; + uint8_t out_ep; + uint8_t state; + uint8_t ctl_protocol; + uint8_t ctl_idle_state; + uint8_t ctl_alt_setting; + uint8_t *desc; + const uint8_t *report_desc; +} usbd_hid_state_t; typedef struct _usbd_cdc_msc_hid_state_t { USBD_HandleTypeDef *pdev; uint8_t usbd_mode; - uint8_t hid_in_ep; - uint8_t hid_out_ep; - uint8_t hid_iface_num; uint8_t usbd_config_desc_size; - uint8_t *hid_desc; - const uint8_t *hid_report_desc; USBD_MSC_BOT_HandleTypeDef MSC_BOT_ClassData; - USBD_HID_HandleTypeDef HID_ClassData; // RAM to hold the current descriptors, which we configure on the fly __ALIGN_BEGIN uint8_t usbd_device_desc[USB_LEN_DEV_DESC] __ALIGN_END; @@ -124,7 +124,7 @@ typedef struct _usbd_cdc_msc_hid_state_t { __ALIGN_BEGIN uint8_t usbd_config_desc[MAX_TEMPLATE_CONFIG_DESC_SIZE] __ALIGN_END; usbd_cdc_state_t *cdc; - void *hid; + usbd_hid_state_t *hid; } usbd_cdc_msc_hid_state_t; #define USBD_HID_MOUSE_MAX_PACKET (4) @@ -185,8 +185,7 @@ int8_t usbd_cdc_control(usbd_cdc_state_t *cdc, uint8_t cmd, uint8_t* pbuf, uint1 int8_t usbd_cdc_receive(usbd_cdc_state_t *cdc, size_t len); // These are provided externally to implement the HID interface -struct _usbd_hid_itf_t; -uint8_t *usbd_hid_init(struct _usbd_hid_itf_t *hid, usbd_cdc_msc_hid_state_t *usbd); -int8_t usbd_hid_receive(struct _usbd_hid_itf_t *hid, size_t len); +uint8_t *usbd_hid_init(usbd_hid_state_t *hid); +int8_t usbd_hid_receive(usbd_hid_state_t *hid, size_t len); #endif // _USB_CDC_MSC_CORE_H_ diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c index 7944ae7778..9ef92a1a6e 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -624,10 +624,10 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode usbd->usbd_config_desc_size = sizeof(cdc_hid_template_config_desc); memcpy(usbd->usbd_config_desc, cdc_hid_template_config_desc, sizeof(cdc_hid_template_config_desc)); usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_HID; - usbd->hid_in_ep = HID_IN_EP_WITH_CDC; - usbd->hid_out_ep = HID_OUT_EP_WITH_CDC; - usbd->hid_iface_num = HID_IFACE_NUM_WITH_CDC; - usbd->hid_desc = usbd->usbd_config_desc + CDC_HID_TEMPLATE_HID_DESC_OFFSET; + usbd->hid->in_ep = HID_IN_EP_WITH_CDC; + usbd->hid->out_ep = HID_OUT_EP_WITH_CDC; + usbd->hid->iface_num = HID_IFACE_NUM_WITH_CDC; + usbd->hid->desc = usbd->usbd_config_desc + CDC_HID_TEMPLATE_HID_DESC_OFFSET; break; case USBD_MODE_CDC: @@ -652,7 +652,7 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode // configure the HID descriptor, if needed if (usbd->usbd_mode & USBD_MODE_HID) { - uint8_t *hid_desc = usbd->hid_desc; + uint8_t *hid_desc = usbd->hid->desc; hid_desc[HID_DESC_OFFSET_SUBCLASS] = hid_info->subclass; hid_desc[HID_DESC_OFFSET_PROTOCOL] = hid_info->protocol; hid_desc[HID_DESC_OFFSET_REPORT_DESC_LEN] = hid_info->report_desc_len; @@ -662,7 +662,7 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO] = hid_info->max_packet_len; hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] = 0; hid_desc[HID_DESC_OFFSET_POLLING_INTERVAL_OUT] = hid_info->polling_interval; - usbd->hid_report_desc = hid_info->report_desc; + usbd->hid->report_desc = hid_info->report_desc; } return 0; @@ -739,30 +739,26 @@ static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { // get max packet lengths from descriptor uint16_t mps_in = - usbd->hid_desc[HID_DESC_OFFSET_MAX_PACKET_LO] - | (usbd->hid_desc[HID_DESC_OFFSET_MAX_PACKET_HI] << 8); + usbd->hid->desc[HID_DESC_OFFSET_MAX_PACKET_LO] + | (usbd->hid->desc[HID_DESC_OFFSET_MAX_PACKET_HI] << 8); uint16_t mps_out = - usbd->hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO] - | (usbd->hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] << 8); + usbd->hid->desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO] + | (usbd->hid->desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] << 8); // Open EP IN - USBD_LL_OpenEP(pdev, - usbd->hid_in_ep, - USBD_EP_TYPE_INTR, - mps_in); + USBD_LL_OpenEP(pdev, usbd->hid->in_ep, USBD_EP_TYPE_INTR, mps_in); // Open EP OUT - USBD_LL_OpenEP(pdev, - usbd->hid_out_ep, - USBD_EP_TYPE_INTR, - mps_out); + USBD_LL_OpenEP(pdev, usbd->hid->out_ep, USBD_EP_TYPE_INTR, mps_out); - uint8_t *buf = usbd_hid_init(usbd->hid, usbd); + + usbd->hid->usbd = usbd; + uint8_t *buf = usbd_hid_init(usbd->hid); // Prepare Out endpoint to receive next packet - USBD_LL_PrepareReceive(pdev, usbd->hid_out_ep, buf, mps_out); + USBD_LL_PrepareReceive(pdev, usbd->hid->out_ep, buf, mps_out); - usbd->HID_ClassData.state = HID_IDLE; + usbd->hid->state = HID_IDLE; } return 0; @@ -795,8 +791,8 @@ static uint8_t USBD_CDC_MSC_HID_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) // HID component // close endpoints - USBD_LL_CloseEP(pdev, usbd->hid_in_ep); - USBD_LL_CloseEP(pdev, usbd->hid_out_ep); + USBD_LL_CloseEP(pdev, usbd->hid->in_ep); + USBD_LL_CloseEP(pdev, usbd->hid->out_ep); } return 0; @@ -832,7 +828,7 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp recipient = USBD_MODE_CDC; } else if ((mode & USBD_MODE_MSC) && iface == MSC_IFACE_NUM_WITH_CDC) { recipient = USBD_MODE_MSC; - } else if ((mode & USBD_MODE_HID) && iface == usbd->hid_iface_num) { + } else if ((mode & USBD_MODE_HID) && iface == usbd->hid->iface_num) { recipient = USBD_MODE_HID; } break; @@ -843,7 +839,7 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp recipient = USBD_MODE_CDC; } else if ((mode & USBD_MODE_MSC) && ep == MSC_OUT_EP) { recipient = USBD_MODE_MSC; - } else if ((mode & USBD_MODE_HID) && ep == usbd->hid_out_ep) { + } else if ((mode & USBD_MODE_HID) && ep == usbd->hid->out_ep) { recipient = USBD_MODE_HID; } break; @@ -905,19 +901,19 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp } else if (recipient == USBD_MODE_HID) { switch (req->bRequest) { case HID_REQ_SET_PROTOCOL: - usbd->HID_ClassData.Protocol = (uint8_t)(req->wValue); + usbd->hid->ctl_protocol = (uint8_t)(req->wValue); break; case HID_REQ_GET_PROTOCOL: - USBD_CtlSendData(pdev, (uint8_t *)&usbd->HID_ClassData.Protocol, 1); + USBD_CtlSendData(pdev, &usbd->hid->ctl_protocol, 1); break; case HID_REQ_SET_IDLE: - usbd->HID_ClassData.IdleState = (uint8_t)(req->wValue >> 8); + usbd->hid->ctl_idle_state = (uint8_t)(req->wValue >> 8); break; case HID_REQ_GET_IDLE: - USBD_CtlSendData(pdev, (uint8_t *)&usbd->HID_ClassData.IdleState, 1); + USBD_CtlSendData(pdev, &usbd->hid->ctl_idle_state, 1); break; default: @@ -961,23 +957,23 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp uint16_t len = 0; const uint8_t *pbuf = NULL; if (req->wValue >> 8 == HID_REPORT_DESC) { - len = usbd->hid_desc[HID_DESC_OFFSET_REPORT_DESC_LEN]; + len = usbd->hid->desc[HID_DESC_OFFSET_REPORT_DESC_LEN]; len = MIN(len, req->wLength); - pbuf = usbd->hid_report_desc; + pbuf = usbd->hid->report_desc; } else if (req->wValue >> 8 == HID_DESCRIPTOR_TYPE) { len = MIN(HID_SUBDESC_LEN, req->wLength); - pbuf = usbd->hid_desc + HID_DESC_OFFSET_SUBDESC; + pbuf = usbd->hid->desc + HID_DESC_OFFSET_SUBDESC; } USBD_CtlSendData(pdev, (uint8_t*)pbuf, len); break; } case USB_REQ_GET_INTERFACE: - USBD_CtlSendData(pdev, (uint8_t *)&usbd->HID_ClassData.AltSetting, 1); + USBD_CtlSendData(pdev, &usbd->hid->ctl_alt_setting, 1); break; case USB_REQ_SET_INTERFACE: - usbd->HID_ClassData.AltSetting = (uint8_t)(req->wValue); + usbd->hid->ctl_alt_setting = (uint8_t)(req->wValue); break; } } @@ -1009,10 +1005,10 @@ static uint8_t USBD_CDC_MSC_HID_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) } else if ((usbd->usbd_mode & USBD_MODE_MSC) && epnum == (MSC_IN_EP & 0x7f)) { MSC_BOT_DataIn(pdev, epnum); return USBD_OK; - } else if ((usbd->usbd_mode & USBD_MODE_HID) && epnum == (usbd->hid_in_ep & 0x7f)) { + } else if ((usbd->usbd_mode & USBD_MODE_HID) && epnum == (usbd->hid->in_ep & 0x7f)) { /* Ensure that the FIFO is empty before a new transfer, this condition could be caused by a new transfer before the end of the previous transfer */ - usbd->HID_ClassData.state = HID_IDLE; + usbd->hid->state = HID_IDLE; return USBD_OK; } @@ -1033,7 +1029,7 @@ static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) } else if ((usbd->usbd_mode & USBD_MODE_MSC) && epnum == (MSC_OUT_EP & 0x7f)) { MSC_BOT_DataOut(pdev, epnum); return USBD_OK; - } else if ((usbd->usbd_mode & USBD_MODE_HID) && epnum == (usbd->hid_out_ep & 0x7f)) { + } else if ((usbd->usbd_mode & USBD_MODE_HID) && epnum == (usbd->hid->out_ep & 0x7f)) { size_t len = USBD_LL_GetRxDataSize(pdev, epnum); usbd_hid_receive(usbd->hid, len); } @@ -1147,22 +1143,22 @@ uint8_t USBD_HID_ReceivePacket(usbd_cdc_msc_hid_state_t *usbd, uint8_t *buf) { // Prepare Out endpoint to receive next packet uint16_t mps_out = - usbd->hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO] - | (usbd->hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] << 8); - USBD_LL_PrepareReceive(usbd->pdev, usbd->hid_out_ep, buf, mps_out); + usbd->hid->desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO] + | (usbd->hid->desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] << 8); + USBD_LL_PrepareReceive(usbd->pdev, usbd->hid->out_ep, buf, mps_out); return USBD_OK; } int USBD_HID_CanSendReport(usbd_cdc_msc_hid_state_t *usbd) { - return usbd->pdev->dev_state == USBD_STATE_CONFIGURED && usbd->HID_ClassData.state == HID_IDLE; + return usbd->pdev->dev_state == USBD_STATE_CONFIGURED && usbd->hid->state == HID_IDLE; } uint8_t USBD_HID_SendReport(usbd_cdc_msc_hid_state_t *usbd, uint8_t *report, uint16_t len) { if (usbd->pdev->dev_state == USBD_STATE_CONFIGURED) { - if (usbd->HID_ClassData.state == HID_IDLE) { - usbd->HID_ClassData.state = HID_BUSY; - USBD_LL_Transmit(usbd->pdev, usbd->hid_in_ep, report, len); + if (usbd->hid->state == HID_IDLE) { + usbd->hid->state = HID_BUSY; + USBD_LL_Transmit(usbd->pdev, usbd->hid->in_ep, report, len); return USBD_OK; } } From 68271a27e658e0d1ee6c70010cc1d469edd5f7d9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 14 May 2018 16:53:45 +1000 Subject: [PATCH 651/828] stm32/usb: Make CDC endpoint definitions private to core usbdev driver. --- ports/stm32/usbd_cdc_interface.c | 2 +- ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h | 6 +----- ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 9 +++++++++ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c index a987646e7a..f6590ade52 100644 --- a/ports/stm32/usbd_cdc_interface.c +++ b/ports/stm32/usbd_cdc_interface.c @@ -165,7 +165,7 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { // doing other things and we must give it a chance to read our data. if (cdc->tx_buf_ptr_wait_count < 500) { USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; - if (USBx_INEP(CDC_IN_EP & 0x7f)->DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ) { + if (USBx_INEP(cdc->base.in_ep & 0x7f)->DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ) { // USB in-endpoint is still reading the data cdc->tx_buf_ptr_wait_count++; return; diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h index 18c2c56c3c..b9671ef3a6 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -39,17 +39,13 @@ #define MSC_IN_EP (0x81) #define MSC_OUT_EP (0x01) -// Need to define here for usbd_cdc_interface.c (it needs CDC_IN_EP) -#define CDC_IN_EP (0x83) -#define CDC_OUT_EP (0x03) -#define CDC_CMD_EP (0x82) - struct _usbd_cdc_msc_hid_state_t; typedef struct { struct _usbd_cdc_msc_hid_state_t *usbd; // The parent USB device uint32_t ctl_packet_buf[CDC_DATA_MAX_PACKET_SIZE / 4]; // Force 32-bit alignment uint8_t iface_num; + uint8_t in_ep; uint8_t cur_request; uint8_t cur_length; volatile uint8_t tx_in_progress; diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c index 9ef92a1a6e..c2030043fb 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -61,6 +61,11 @@ #define MSC_IFACE_NUM_WITH_CDC (0) #define HID_IFACE_NUM_WITH_CDC (0) #define HID_IFACE_NUM_WITH_MSC (1) + +#define CDC_IN_EP (0x83) +#define CDC_OUT_EP (0x03) +#define CDC_CMD_EP (0x82) + #define HID_IN_EP_WITH_CDC (0x81) #define HID_OUT_EP_WITH_CDC (0x01) #define HID_IN_EP_WITH_MSC (0x83) @@ -650,6 +655,10 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode return -1; } + if (usbd->usbd_mode & USBD_MODE_CDC) { + usbd->cdc->in_ep = CDC_IN_EP; + } + // configure the HID descriptor, if needed if (usbd->usbd_mode & USBD_MODE_HID) { uint8_t *hid_desc = usbd->hid->desc; From 91bca340ec0a6d8c91ba4a31d25a23c81ba2c044 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 14 May 2018 16:55:04 +1000 Subject: [PATCH 652/828] stm32/usb: Change CDC tx/rx funcs to take CDC state, not usbdev state. --- ports/stm32/usbd_cdc_interface.c | 4 ++-- ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h | 4 ++-- ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 14 +++++++------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c index f6590ade52..3ab6157c46 100644 --- a/ports/stm32/usbd_cdc_interface.c +++ b/ports/stm32/usbd_cdc_interface.c @@ -186,7 +186,7 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { buffptr = cdc->tx_buf_ptr_out_shadow; - if (USBD_CDC_TransmitPacket(cdc->base.usbd, buffsize, &cdc->tx_buf[buffptr]) == USBD_OK) { + if (USBD_CDC_TransmitPacket(&cdc->base, buffsize, &cdc->tx_buf[buffptr]) == USBD_OK) { cdc->tx_buf_ptr_out_shadow += buffsize; if (cdc->tx_buf_ptr_out_shadow == USBD_CDC_TX_DATA_SIZE) { cdc->tx_buf_ptr_out_shadow = 0; @@ -226,7 +226,7 @@ int8_t usbd_cdc_receive(usbd_cdc_state_t *cdc_in, size_t len) { } // initiate next USB packet transfer - USBD_CDC_ReceivePacket(cdc->base.usbd, cdc->rx_packet_buf); + USBD_CDC_ReceivePacket(&cdc->base, cdc->rx_packet_buf); return USBD_OK; } diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h index b9671ef3a6..d56bdf6b2c 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -162,8 +162,8 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode // returns the current usb mode uint8_t USBD_GetMode(usbd_cdc_msc_hid_state_t *usbd); -uint8_t USBD_CDC_ReceivePacket(usbd_cdc_msc_hid_state_t *usbd, uint8_t *buf); -uint8_t USBD_CDC_TransmitPacket(usbd_cdc_msc_hid_state_t *usbd, size_t len, const uint8_t *buf); +uint8_t USBD_CDC_ReceivePacket(usbd_cdc_state_t *cdc, uint8_t *buf); +uint8_t USBD_CDC_TransmitPacket(usbd_cdc_state_t *cdc, size_t len, const uint8_t *buf); static inline void USBD_MSC_RegisterStorage(usbd_cdc_msc_hid_state_t *usbd, USBD_StorageTypeDef *fops) { usbd->MSC_BOT_ClassData.bdev_ops = fops; diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c index c2030043fb..3e27d1c6c5 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -1111,13 +1111,13 @@ uint8_t *USBD_CDC_MSC_HID_GetDeviceQualifierDescriptor(USBD_HandleTypeDef *pdev, } // data received on non-control OUT endpoint -uint8_t USBD_CDC_TransmitPacket(usbd_cdc_msc_hid_state_t *usbd, size_t len, const uint8_t *buf) { - if (usbd->cdc->tx_in_progress == 0) { +uint8_t USBD_CDC_TransmitPacket(usbd_cdc_state_t *cdc, size_t len, const uint8_t *buf) { + if (cdc->tx_in_progress == 0) { // transmit next packet - USBD_LL_Transmit(usbd->pdev, CDC_IN_EP, (uint8_t*)buf, len); + USBD_LL_Transmit(cdc->usbd->pdev, cdc->in_ep, (uint8_t*)buf, len); // Tx transfer in progress - usbd->cdc->tx_in_progress = 1; + cdc->tx_in_progress = 1; return USBD_OK; } else { return USBD_BUSY; @@ -1125,17 +1125,17 @@ uint8_t USBD_CDC_TransmitPacket(usbd_cdc_msc_hid_state_t *usbd, size_t len, cons } // prepare OUT endpoint for reception -uint8_t USBD_CDC_ReceivePacket(usbd_cdc_msc_hid_state_t *usbd, uint8_t *buf) { +uint8_t USBD_CDC_ReceivePacket(usbd_cdc_state_t *cdc, uint8_t *buf) { // Suspend or Resume USB Out process #if !USBD_SUPPORT_HS_MODE - if (usbd->pdev->dev_speed == USBD_SPEED_HIGH) { + if (cdc->usbd->pdev->dev_speed == USBD_SPEED_HIGH) { return USBD_FAIL; } #endif // Prepare Out endpoint to receive next packet - USBD_LL_PrepareReceive(usbd->pdev, CDC_OUT_EP, buf, usbd_cdc_max_packet(usbd->pdev)); + USBD_LL_PrepareReceive(cdc->usbd->pdev, CDC_OUT_EP, buf, usbd_cdc_max_packet(cdc->usbd->pdev)); return USBD_OK; } From 2e565cc0d47f464ea02292ef4c23f12421a90169 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 14 May 2018 17:04:43 +1000 Subject: [PATCH 653/828] stm32/usb: Change HID report funcs to take HID state, not usbdev state. --- ports/stm32/usb.c | 4 +-- ports/stm32/usbd_hid_interface.c | 6 ++-- .../stm32/usbdev/class/inc/usbd_cdc_msc_hid.h | 10 +++--- .../stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 32 +++++++++---------- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index e253cf0118..7e30805cce 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -628,7 +628,7 @@ STATIC mp_obj_t pyb_usb_hid_send(mp_obj_t self_in, mp_obj_t report_in) { } // send the data - if (USBD_OK == USBD_HID_SendReport(&self->usb_dev->usbd_cdc_msc_hid_state, bufinfo.buf, bufinfo.len)) { + if (USBD_OK == USBD_HID_SendReport(&self->usb_dev->usbd_hid_itf.base, bufinfo.buf, bufinfo.len)) { return mp_obj_new_int(bufinfo.len); } else { return mp_obj_new_int(0); @@ -660,7 +660,7 @@ STATIC mp_uint_t pyb_usb_hid_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_ if ((flags & MP_STREAM_POLL_RD) && usbd_hid_rx_num(&self->usb_dev->usbd_hid_itf) > 0) { ret |= MP_STREAM_POLL_RD; } - if ((flags & MP_STREAM_POLL_WR) && USBD_HID_CanSendReport(&self->usb_dev->usbd_cdc_msc_hid_state)) { + if ((flags & MP_STREAM_POLL_WR) && USBD_HID_CanSendReport(&self->usb_dev->usbd_hid_itf.base)) { ret |= MP_STREAM_POLL_WR; } } else { diff --git a/ports/stm32/usbd_hid_interface.c b/ports/stm32/usbd_hid_interface.c index d8c160fe7b..3ffc0b425d 100644 --- a/ports/stm32/usbd_hid_interface.c +++ b/ports/stm32/usbd_hid_interface.c @@ -62,9 +62,9 @@ int8_t usbd_hid_receive(usbd_hid_state_t *hid_in, size_t len) { hid->current_write_buffer = !hid->current_write_buffer; hid->last_read_len = len; // initiate next USB packet transfer, to append to existing data in buffer - USBD_HID_ReceivePacket(hid->base.usbd, hid->buffer[hid->current_write_buffer]); + USBD_HID_ReceivePacket(&hid->base, hid->buffer[hid->current_write_buffer]); // Set NAK to indicate we need to process read buffer - USBD_HID_SetNAK(hid->base.usbd); + USBD_HID_SetNAK(&hid->base); return USBD_OK; } @@ -102,7 +102,7 @@ int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout) hid->current_read_buffer = !hid->current_read_buffer; // Clear NAK to indicate we are ready to read more data - USBD_HID_ClearNAK(hid->base.usbd); + USBD_HID_ClearNAK(&hid->base); // Success, return number of bytes read return read_len; diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h index d56bdf6b2c..8bf454558a 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -169,11 +169,11 @@ static inline void USBD_MSC_RegisterStorage(usbd_cdc_msc_hid_state_t *usbd, USBD usbd->MSC_BOT_ClassData.bdev_ops = fops; } -uint8_t USBD_HID_ReceivePacket(usbd_cdc_msc_hid_state_t *usbd, uint8_t *buf); -int USBD_HID_CanSendReport(usbd_cdc_msc_hid_state_t *usbd); -uint8_t USBD_HID_SendReport(usbd_cdc_msc_hid_state_t *usbd, uint8_t *report, uint16_t len); -uint8_t USBD_HID_SetNAK(usbd_cdc_msc_hid_state_t *usbd); -uint8_t USBD_HID_ClearNAK(usbd_cdc_msc_hid_state_t *usbd); +uint8_t USBD_HID_ReceivePacket(usbd_hid_state_t *usbd, uint8_t *buf); +int USBD_HID_CanSendReport(usbd_hid_state_t *usbd); +uint8_t USBD_HID_SendReport(usbd_hid_state_t *usbd, uint8_t *report, uint16_t len); +uint8_t USBD_HID_SetNAK(usbd_hid_state_t *usbd); +uint8_t USBD_HID_ClearNAK(usbd_hid_state_t *usbd); // These are provided externally to implement the CDC interface uint8_t *usbd_cdc_init(usbd_cdc_state_t *cdc); diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c index 3e27d1c6c5..6def258c60 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -1141,51 +1141,51 @@ uint8_t USBD_CDC_ReceivePacket(usbd_cdc_state_t *cdc, uint8_t *buf) { } // prepare OUT endpoint for reception -uint8_t USBD_HID_ReceivePacket(usbd_cdc_msc_hid_state_t *usbd, uint8_t *buf) { +uint8_t USBD_HID_ReceivePacket(usbd_hid_state_t *hid, uint8_t *buf) { // Suspend or Resume USB Out process #if !USBD_SUPPORT_HS_MODE - if (usbd->pdev->dev_speed == USBD_SPEED_HIGH) { + if (hid->usbd->pdev->dev_speed == USBD_SPEED_HIGH) { return USBD_FAIL; } #endif // Prepare Out endpoint to receive next packet uint16_t mps_out = - usbd->hid->desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO] - | (usbd->hid->desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] << 8); - USBD_LL_PrepareReceive(usbd->pdev, usbd->hid->out_ep, buf, mps_out); + hid->desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO] + | (hid->desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] << 8); + USBD_LL_PrepareReceive(hid->usbd->pdev, hid->out_ep, buf, mps_out); return USBD_OK; } -int USBD_HID_CanSendReport(usbd_cdc_msc_hid_state_t *usbd) { - return usbd->pdev->dev_state == USBD_STATE_CONFIGURED && usbd->hid->state == HID_IDLE; +int USBD_HID_CanSendReport(usbd_hid_state_t *hid) { + return hid->usbd->pdev->dev_state == USBD_STATE_CONFIGURED && hid->state == HID_IDLE; } -uint8_t USBD_HID_SendReport(usbd_cdc_msc_hid_state_t *usbd, uint8_t *report, uint16_t len) { - if (usbd->pdev->dev_state == USBD_STATE_CONFIGURED) { - if (usbd->hid->state == HID_IDLE) { - usbd->hid->state = HID_BUSY; - USBD_LL_Transmit(usbd->pdev, usbd->hid->in_ep, report, len); +uint8_t USBD_HID_SendReport(usbd_hid_state_t *hid, uint8_t *report, uint16_t len) { + if (hid->usbd->pdev->dev_state == USBD_STATE_CONFIGURED) { + if (hid->state == HID_IDLE) { + hid->state = HID_BUSY; + USBD_LL_Transmit(hid->usbd->pdev, hid->in_ep, report, len); return USBD_OK; } } return USBD_FAIL; } -uint8_t USBD_HID_SetNAK(usbd_cdc_msc_hid_state_t *usbd) { +uint8_t USBD_HID_SetNAK(usbd_hid_state_t *hid) { // get USBx object from pdev (needed for USBx_OUTEP macro below) - PCD_HandleTypeDef *hpcd = usbd->pdev->pData; + PCD_HandleTypeDef *hpcd = hid->usbd->pdev->pData; USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; // set NAK on HID OUT endpoint USBx_OUTEP(HID_OUT_EP_WITH_CDC)->DOEPCTL |= USB_OTG_DOEPCTL_SNAK; return USBD_OK; } -uint8_t USBD_HID_ClearNAK(usbd_cdc_msc_hid_state_t *usbd) { +uint8_t USBD_HID_ClearNAK(usbd_hid_state_t *hid) { // get USBx object from pdev (needed for USBx_OUTEP macro below) - PCD_HandleTypeDef *hpcd = usbd->pdev->pData; + PCD_HandleTypeDef *hpcd = hid->usbd->pdev->pData; USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; // clear NAK on HID OUT endpoint USBx_OUTEP(HID_OUT_EP_WITH_CDC)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; From 47ecbbbecbad117820e1c37282e7e61528e5d969 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 14 May 2018 23:44:45 +1000 Subject: [PATCH 654/828] stm32/usb: Add ability to have 2x VCP interfaces on the one USB device. This patch adds the configuration MICROPY_HW_USB_ENABLE_CDC2 which enables a new USB device configuration at runtime: VCP+VCP+MSC. It will give two independent VCP interfaces available via pyb.USB_VCP(0) and pyb.USB_VCP(1). The first one is the usual one and has the REPL on it. The second one is available for general use. This configuration is disabled by default because if the mode is not used then it takes up about 2200 bytes of RAM. Also, F4 MCUs can't support this mode on their USB FS peripheral (eg PYBv1.x) because they don't have enough endpoints. The USB HS peripheral of an F4 supports it, as well as both the USB FS and USB HS peripherals of F7 MCUs. --- ports/stm32/usb.c | 42 +++- ports/stm32/usb.h | 1 + ports/stm32/usbd_cdc_interface.c | 22 +- ports/stm32/usbd_cdc_interface.h | 4 + ports/stm32/usbd_conf.c | 42 +++- ports/stm32/usbd_conf.h | 2 +- .../stm32/usbdev/class/inc/usbd_cdc_msc_hid.h | 8 + .../usbdev/class/inc/usbd_cdc_msc_hid0.h | 8 +- .../stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 203 +++++++++++++----- 9 files changed, 257 insertions(+), 75 deletions(-) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 7e30805cce..23c490d375 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -63,6 +63,9 @@ typedef struct _usb_device_t { USBD_HandleTypeDef hUSBDDevice; usbd_cdc_msc_hid_state_t usbd_cdc_msc_hid_state; usbd_cdc_itf_t usbd_cdc_itf; + #if MICROPY_HW_USB_ENABLE_CDC2 + usbd_cdc_itf_t usbd_cdc2_itf; + #endif usbd_hid_itf_t usbd_hid_itf; } usb_device_t; @@ -127,6 +130,9 @@ bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_H usbd->pClass = &USBD_CDC_MSC_HID; usb_dev->usbd_cdc_msc_hid_state.pdev = usbd; usb_dev->usbd_cdc_msc_hid_state.cdc = &usb_dev->usbd_cdc_itf.base; + #if MICROPY_HW_USB_ENABLE_CDC2 + usb_dev->usbd_cdc_msc_hid_state.cdc2 = &usb_dev->usbd_cdc2_itf.base; + #endif usb_dev->usbd_cdc_msc_hid_state.hid = &usb_dev->usbd_hid_itf.base; usbd->pClassData = &usb_dev->usbd_cdc_msc_hid_state; @@ -178,6 +184,15 @@ void usb_vcp_send_strn(const char *str, int len) { } } +usbd_cdc_itf_t *usb_vcp_get(int idx) { + #if MICROPY_HW_USB_ENABLE_CDC2 + if (idx == 1) { + return &usb_device.usbd_cdc2_itf; + } + #endif + return &usb_device.usbd_cdc_itf; +} + /******************************************************************************/ // MicroPython bindings for USB @@ -285,6 +300,13 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * pid = USBD_PID_CDC_MSC; } mode = USBD_MODE_CDC_MSC; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if (strcmp(mode_str, "VCP+VCP+MSC") == 0) { + if (args[2].u_int == -1) { + pid = USBD_PID_CDC2_MSC; + } + mode = USBD_MODE_CDC2_MSC; + #endif } else if (strcmp(mode_str, "CDC+HID") == 0 || strcmp(mode_str, "VCP+HID") == 0) { if (args[2].u_int == -1) { pid = USBD_PID_CDC_HID; @@ -358,21 +380,33 @@ typedef struct _pyb_usb_vcp_obj_t { } pyb_usb_vcp_obj_t; STATIC const pyb_usb_vcp_obj_t pyb_usb_vcp_obj = {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc_itf}; +#if MICROPY_HW_USB_ENABLE_CDC2 +STATIC const pyb_usb_vcp_obj_t pyb_usb_vcp2_obj = {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc2_itf}; +#endif STATIC void pyb_usb_vcp_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - mp_print_str(print, "USB_VCP()"); + int id = ((pyb_usb_vcp_obj_t*)self_in)->cdc_itf - &usb_device.usbd_cdc_itf; + mp_printf(print, "USB_VCP(%u)", id); } /// \classmethod \constructor() /// Create a new USB_VCP object. STATIC mp_obj_t pyb_usb_vcp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { // check arguments - mp_arg_check_num(n_args, n_kw, 0, 0, false); + mp_arg_check_num(n_args, n_kw, 0, 1, false); // TODO raise exception if USB is not configured for VCP - // return the USB VCP object - return (mp_obj_t)&pyb_usb_vcp_obj; + int id = (n_args == 0) ? 0 : mp_obj_get_int(args[0]); + if (id == 0) { + return MP_OBJ_FROM_PTR(&pyb_usb_vcp_obj); + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if (id == 1) { + return MP_OBJ_FROM_PTR(&pyb_usb_vcp2_obj); + #endif + } else { + mp_raise_ValueError(NULL); + } } STATIC mp_obj_t pyb_usb_vcp_setinterrupt(mp_obj_t self_in, mp_obj_t int_chr_in) { diff --git a/ports/stm32/usb.h b/ports/stm32/usb.h index 6b43af00fa..1de9e5d0e5 100644 --- a/ports/stm32/usb.h +++ b/ports/stm32/usb.h @@ -36,6 +36,7 @@ #define USBD_PID_CDC_HID (0x9801) #define USBD_PID_CDC (0x9802) #define USBD_PID_MSC (0x9803) +#define USBD_PID_CDC2_MSC (0x9804) typedef enum { PYB_USB_STORAGE_MEDIUM_NONE = 0, diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c index 3ab6157c46..4c464dbf33 100644 --- a/ports/stm32/usbd_cdc_interface.c +++ b/ports/stm32/usbd_cdc_interface.c @@ -69,6 +69,11 @@ uint8_t *usbd_cdc_init(usbd_cdc_state_t *cdc_in) { cdc->tx_buf_ptr_wait_count = 0; cdc->tx_need_empty_packet = 0; cdc->dev_is_connected = 0; + #if MICROPY_HW_USB_ENABLE_CDC2 + cdc->attached_to_repl = &cdc->base == cdc->base.usbd->cdc; + #else + cdc->attached_to_repl = 1; + #endif // Return the buffer to place the first USB OUT packet return cdc->rx_packet_buf; @@ -143,10 +148,7 @@ int8_t usbd_cdc_control(usbd_cdc_state_t *cdc_in, uint8_t cmd, uint8_t* pbuf, ui // This function is called to process outgoing data. We hook directly into the // SOF (start of frame) callback so that it is called exactly at the time it is // needed (reducing latency), and often enough (increasing bandwidth). -void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { - usbd_cdc_msc_hid_state_t *usbd = ((USBD_HandleTypeDef*)hpcd->pData)->pClassData; - usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)usbd->cdc; - +static void usbd_cdc_sof(PCD_HandleTypeDef *hpcd, usbd_cdc_itf_t *cdc) { if (cdc == NULL || !cdc->dev_is_connected) { // CDC device is not connected to a host, so we are unable to send any data return; @@ -199,11 +201,19 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { // the host waits for all data to arrive (ie, waits for a packet < max packet size). // To flush a packet of exactly max packet size, we need to send a zero-size packet. // See eg http://www.cypress.com/?id=4&rID=92719 - cdc->tx_need_empty_packet = (buffsize > 0 && buffsize % usbd_cdc_max_packet(usbd->pdev) == 0 && cdc->tx_buf_ptr_out_shadow == cdc->tx_buf_ptr_in); + cdc->tx_need_empty_packet = (buffsize > 0 && buffsize % usbd_cdc_max_packet(cdc->base.usbd->pdev) == 0 && cdc->tx_buf_ptr_out_shadow == cdc->tx_buf_ptr_in); } } } +void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { + usbd_cdc_msc_hid_state_t *usbd = ((USBD_HandleTypeDef*)hpcd->pData)->pClassData; + usbd_cdc_sof(hpcd, (usbd_cdc_itf_t*)usbd->cdc); + #if MICROPY_HW_USB_ENABLE_CDC2 + usbd_cdc_sof(hpcd, (usbd_cdc_itf_t*)usbd->cdc2); + #endif +} + // Data received over USB OUT endpoint is processed here. // len: number of bytes received into the buffer we passed to USBD_CDC_ReceivePacket // Returns USBD_OK if all operations are OK else USBD_FAIL @@ -212,7 +222,7 @@ int8_t usbd_cdc_receive(usbd_cdc_state_t *cdc_in, size_t len) { // copy the incoming data into the circular buffer for (const uint8_t *src = cdc->rx_packet_buf, *top = cdc->rx_packet_buf + len; src < top; ++src) { - if (mp_interrupt_char != -1 && *src == mp_interrupt_char) { + if (cdc->attached_to_repl && mp_interrupt_char != -1 && *src == mp_interrupt_char) { pendsv_kbd_intr(); } else { uint16_t next_put = (cdc->rx_buf_put + 1) & (USBD_CDC_RX_DATA_SIZE - 1); diff --git a/ports/stm32/usbd_cdc_interface.h b/ports/stm32/usbd_cdc_interface.h index bfcdfaf333..cdf556d4ec 100644 --- a/ports/stm32/usbd_cdc_interface.h +++ b/ports/stm32/usbd_cdc_interface.h @@ -50,8 +50,12 @@ typedef struct _usbd_cdc_itf_t { uint8_t tx_need_empty_packet; // used to flush the USB IN endpoint if the last packet was exactly the endpoint packet size volatile uint8_t dev_is_connected; // indicates if we are connected + uint8_t attached_to_repl; // indicates if interface is connected to REPL } usbd_cdc_itf_t; +// This is implemented in usb.c +usbd_cdc_itf_t *usb_vcp_get(int idx); + static inline int usbd_cdc_is_connected(usbd_cdc_itf_t *cdc) { return cdc->dev_is_connected; } diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index d4a09459b8..7829dcce68 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -368,7 +368,11 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { if (pdev->id == USB_PHY_FS_ID) { // Set LL Driver parameters pcd_fs_handle.Instance = USB_OTG_FS; + #if MICROPY_HW_USB_ENABLE_CDC2 + pcd_fs_handle.Init.dev_endpoints = 6; + #else pcd_fs_handle.Init.dev_endpoints = 4; + #endif pcd_fs_handle.Init.use_dedicated_ep1 = 0; pcd_fs_handle.Init.ep0_mps = 0x40; pcd_fs_handle.Init.dma_enable = 0; @@ -393,11 +397,22 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { // Initialize LL Driver HAL_PCD_Init(&pcd_fs_handle); - HAL_PCD_SetRxFiFo(&pcd_fs_handle, 0x80); - HAL_PCD_SetTxFiFo(&pcd_fs_handle, 0, 0x20); - HAL_PCD_SetTxFiFo(&pcd_fs_handle, 1, 0x40); - HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 0x20); - HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 0x40); + // We have 320 32-bit words in total to use here + #if MICROPY_HW_USB_ENABLE_CDC2 + HAL_PCD_SetRxFiFo(&pcd_fs_handle, 128); + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 0, 32); // EP0 + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 1, 64); // MSC / HID + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 16); // CDC CMD + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 32); // CDC DATA + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 4, 16); // CDC2 CMD + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 5, 32); // CDC2 DATA + #else + HAL_PCD_SetRxFiFo(&pcd_fs_handle, 128); + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 0, 32); // EP0 + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 1, 64); // MSC / HID + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 32); // CDC CMD + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 64); // CDC DATA + #endif } #endif #if MICROPY_HW_USB_HS @@ -406,11 +421,13 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { // Set LL Driver parameters pcd_hs_handle.Instance = USB_OTG_HS; - pcd_hs_handle.Init.dev_endpoints = 4; + pcd_hs_handle.Init.dev_endpoints = 6; pcd_hs_handle.Init.use_dedicated_ep1 = 0; pcd_hs_handle.Init.ep0_mps = 0x40; pcd_hs_handle.Init.dma_enable = 0; pcd_hs_handle.Init.low_power_enable = 0; + pcd_hs_handle.Init.lpm_enable = DISABLE; + pcd_hs_handle.Init.battery_charging_enable = DISABLE; #if defined(STM32F723xx) || defined(STM32F733xx) pcd_hs_handle.Init.phy_itface = USB_OTG_HS_EMBEDDED_PHY; #else @@ -436,11 +453,14 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { // Initialize LL Driver HAL_PCD_Init(&pcd_hs_handle); - HAL_PCD_SetRxFiFo(&pcd_hs_handle, 0x200); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 0x20); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 0x100); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 2, 0x20); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 0xc0); + // We have 1024 32-bit words in total to use here + HAL_PCD_SetRxFiFo(&pcd_hs_handle, 512); + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 32); // EP0 + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 256); // MSC / HID + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 2, 32); // CDC CMD + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 64); // CDC DATA + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 4, 32); // CDC2 CMD + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 5, 64); // CDC2 DATA #else // !MICROPY_HW_USB_HS_IN_FS diff --git a/ports/stm32/usbd_conf.h b/ports/stm32/usbd_conf.h index e68cbd9a4b..1f8e754a2b 100644 --- a/ports/stm32/usbd_conf.h +++ b/ports/stm32/usbd_conf.h @@ -37,7 +37,7 @@ #include #include -#define USBD_MAX_NUM_INTERFACES 1 +#define USBD_MAX_NUM_INTERFACES 4 #define USBD_MAX_NUM_CONFIGURATION 1 #define USBD_MAX_STR_DESC_SIZ 0x100 #define USBD_SELF_POWERED 0 diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h index 8bf454558a..a4f81f10d9 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -20,7 +20,11 @@ // Needed for the CDC+MSC+HID state and should be maximum of all template // config descriptors defined in usbd_cdc_msc_hid.c +#if MICROPY_HW_USB_ENABLE_CDC2 +#define MAX_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58)) +#else #define MAX_TEMPLATE_CONFIG_DESC_SIZE (107) +#endif // CDC, MSC and HID packet sizes #define MSC_FS_MAX_PACKET (64) @@ -46,6 +50,7 @@ typedef struct { uint32_t ctl_packet_buf[CDC_DATA_MAX_PACKET_SIZE / 4]; // Force 32-bit alignment uint8_t iface_num; uint8_t in_ep; + uint8_t out_ep; uint8_t cur_request; uint8_t cur_length; volatile uint8_t tx_in_progress; @@ -120,6 +125,9 @@ typedef struct _usbd_cdc_msc_hid_state_t { __ALIGN_BEGIN uint8_t usbd_config_desc[MAX_TEMPLATE_CONFIG_DESC_SIZE] __ALIGN_END; usbd_cdc_state_t *cdc; + #if MICROPY_HW_USB_ENABLE_CDC2 + usbd_cdc_state_t *cdc2; + #endif usbd_hid_state_t *hid; } usbd_cdc_msc_hid_state_t; diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h index 95fc693a00..c876dcf298 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h @@ -34,9 +34,11 @@ typedef enum { USBD_MODE_CDC = 0x01, USBD_MODE_MSC = 0x02, USBD_MODE_HID = 0x04, - USBD_MODE_CDC_MSC = 0x03, - USBD_MODE_CDC_HID = 0x05, - USBD_MODE_MSC_HID = 0x06, + USBD_MODE_CDC2 = 0x08, + USBD_MODE_CDC_MSC = USBD_MODE_CDC | USBD_MODE_MSC, + USBD_MODE_CDC_HID = USBD_MODE_CDC | USBD_MODE_HID, + USBD_MODE_MSC_HID = USBD_MODE_MSC | USBD_MODE_HID, + USBD_MODE_CDC2_MSC = USBD_MODE_CDC | USBD_MODE_MSC | USBD_MODE_CDC2, USBD_MODE_HIGH_SPEED = 0x80, // or with one of the above } usb_device_mode_t; diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c index 6def258c60..d0b922d761 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -34,6 +34,10 @@ #define CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE (98) #define CDC_MSC_TEMPLATE_MSC_DESC_OFFSET (9) #define CDC_MSC_TEMPLATE_CDC_DESC_OFFSET (40) +#define CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58)) +#define CDC2_MSC_TEMPLATE_MSC_DESC_OFFSET (9) +#define CDC2_MSC_TEMPLATE_CDC_DESC_OFFSET (9 + 23 + 8) +#define CDC2_MSC_TEMPLATE_CDC2_DESC_OFFSET (9 + 23 + (8 + 58) + 8) #define CDC_HID_TEMPLATE_CONFIG_DESC_SIZE (107) #define CDC_HID_TEMPLATE_HID_DESC_OFFSET (9) #define CDC_HID_TEMPLATE_CDC_DESC_OFFSET (49) @@ -57,6 +61,7 @@ #define CDC_IFACE_NUM_ALONE (0) #define CDC_IFACE_NUM_WITH_MSC (1) +#define CDC2_IFACE_NUM_WITH_MSC (3) #define CDC_IFACE_NUM_WITH_HID (1) #define MSC_IFACE_NUM_WITH_CDC (0) #define HID_IFACE_NUM_WITH_CDC (0) @@ -66,6 +71,10 @@ #define CDC_OUT_EP (0x03) #define CDC_CMD_EP (0x82) +#define CDC2_IN_EP (0x85) +#define CDC2_OUT_EP (0x05) +#define CDC2_CMD_EP (0x84) + #define HID_IN_EP_WITH_CDC (0x81) #define HID_OUT_EP_WITH_CDC (0x01) #define HID_IN_EP_WITH_MSC (0x83) @@ -625,6 +634,31 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_MSC; break; + #if MICROPY_HW_USB_ENABLE_CDC2 + case USBD_MODE_CDC2_MSC: { + usbd->usbd_config_desc_size = CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE; + uint8_t *d = usbd->usbd_config_desc; + memcpy(d, cdc_msc_template_config_desc, sizeof(cdc_msc_template_config_desc)); + d[2] = LOBYTE(CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE); // wTotalLength + d[3] = HIBYTE(CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE); + d[4] = 5; // bNumInterfaces + memcpy(d + 9 + 23 + (8 + 58), d + 9 + 23, 8 + 58); + d += 9 + 23 + (8 + 58); + d[2] = CDC2_IFACE_NUM_WITH_MSC; // bFirstInterface + d[10] = CDC2_IFACE_NUM_WITH_MSC; // bInterfaceNumber + d[26] = CDC2_IFACE_NUM_WITH_MSC + 1; // bDataInterface + d[34] = CDC2_IFACE_NUM_WITH_MSC + 0; // bMasterInterface + d[35] = CDC2_IFACE_NUM_WITH_MSC + 1; // bSlaveInterface + d[38] = CDC2_CMD_EP; // bEndpointAddress + d[45] = CDC2_IFACE_NUM_WITH_MSC + 1; // bInterfaceNumber + d[54] = CDC2_OUT_EP; // bEndpointAddress + d[61] = CDC2_IN_EP; // bEndpointAddress + usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_MSC; + usbd->cdc2->iface_num = CDC2_IFACE_NUM_WITH_MSC; + break; + } + #endif + case USBD_MODE_CDC_HID: usbd->usbd_config_desc_size = sizeof(cdc_hid_template_config_desc); memcpy(usbd->usbd_config_desc, cdc_hid_template_config_desc, sizeof(cdc_hid_template_config_desc)); @@ -657,8 +691,16 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode if (usbd->usbd_mode & USBD_MODE_CDC) { usbd->cdc->in_ep = CDC_IN_EP; + usbd->cdc->out_ep = CDC_OUT_EP; } + #if MICROPY_HW_USB_ENABLE_CDC2 + if (usbd->usbd_mode & USBD_MODE_CDC2) { + usbd->cdc2->in_ep = CDC2_IN_EP; + usbd->cdc2->out_ep = CDC2_OUT_EP; + } + #endif + // configure the HID descriptor, if needed if (usbd->usbd_mode & USBD_MODE_HID) { uint8_t *hid_desc = usbd->hid->desc; @@ -677,6 +719,26 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode return 0; } +static void usbd_cdc_state_init(USBD_HandleTypeDef *pdev, usbd_cdc_msc_hid_state_t *usbd, usbd_cdc_state_t *cdc, uint8_t cmd_ep) { + int mp = usbd_cdc_max_packet(pdev); + + // Open endpoints + USBD_LL_OpenEP(pdev, cdc->in_ep, USBD_EP_TYPE_BULK, mp); + USBD_LL_OpenEP(pdev, cdc->out_ep, USBD_EP_TYPE_BULK, mp); + USBD_LL_OpenEP(pdev, cmd_ep, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE); + + // Init state + cdc->usbd = usbd; + cdc->cur_request = 0xff; + cdc->tx_in_progress = 0; + + // Init interface + uint8_t *buf = usbd_cdc_init(cdc); + + // Prepare Out endpoint to receive next packet + USBD_LL_PrepareReceive(pdev, cdc->out_ep, buf, mp); +} + static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { #if !USBD_SUPPORT_HS_MODE if (pdev->dev_speed == USBD_SPEED_HIGH) { @@ -689,39 +751,16 @@ static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { if (usbd->usbd_mode & USBD_MODE_CDC) { // CDC VCP component - - int mp = usbd_cdc_max_packet(pdev); - - // Open EP IN - USBD_LL_OpenEP(pdev, - CDC_IN_EP, - USBD_EP_TYPE_BULK, - mp); - - // Open EP OUT - USBD_LL_OpenEP(pdev, - CDC_OUT_EP, - USBD_EP_TYPE_BULK, - mp); - - // Open Command IN EP - USBD_LL_OpenEP(pdev, - CDC_CMD_EP, - USBD_EP_TYPE_INTR, - CDC_CMD_PACKET_SIZE); - - // Init Xfer states - usbd->cdc->usbd = usbd; - usbd->cdc->cur_request = 0xff; - usbd->cdc->tx_in_progress = 0; - - // Init physical Interface components - uint8_t *buf = usbd_cdc_init(usbd->cdc); - - // Prepare Out endpoint to receive next packet - USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, buf, mp); + usbd_cdc_state_init(pdev, usbd, usbd->cdc, CDC_CMD_EP); } + #if MICROPY_HW_USB_ENABLE_CDC2 + if (usbd->usbd_mode & USBD_MODE_CDC2) { + // CDC VCP #2 component + usbd_cdc_state_init(pdev, usbd, usbd->cdc2, CDC2_CMD_EP); + } + #endif + if (usbd->usbd_mode & USBD_MODE_MSC) { // MSC component @@ -785,6 +824,17 @@ static uint8_t USBD_CDC_MSC_HID_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) USBD_LL_CloseEP(pdev, CDC_CMD_EP); } + #if MICROPY_HW_USB_ENABLE_CDC2 + if ((usbd->usbd_mode & USBD_MODE_CDC2) && usbd->cdc2) { + // CDC VCP #2 component + + // close endpoints + USBD_LL_CloseEP(pdev, CDC2_IN_EP); + USBD_LL_CloseEP(pdev, CDC2_OUT_EP); + USBD_LL_CloseEP(pdev, CDC2_CMD_EP); + } + #endif + if (usbd->usbd_mode & USBD_MODE_MSC) { // MSC component @@ -830,11 +880,18 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp // Work out the recipient of the setup request uint8_t mode = usbd->usbd_mode; uint8_t recipient = 0; + usbd_cdc_state_t *cdc; switch (req->bmRequest & USB_REQ_RECIPIENT_MASK) { case USB_REQ_RECIPIENT_INTERFACE: { uint16_t iface = req->wIndex; if ((mode & USBD_MODE_CDC) && iface == usbd->cdc->iface_num) { recipient = USBD_MODE_CDC; + cdc = usbd->cdc; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if ((mode & USBD_MODE_CDC2) && iface == usbd->cdc2->iface_num) { + recipient = USBD_MODE_CDC; + cdc = usbd->cdc2; + #endif } else if ((mode & USBD_MODE_MSC) && iface == MSC_IFACE_NUM_WITH_CDC) { recipient = USBD_MODE_MSC; } else if ((mode & USBD_MODE_HID) && iface == usbd->hid->iface_num) { @@ -846,6 +903,12 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp uint8_t ep = req->wIndex & 0x7f; if ((mode & USBD_MODE_CDC) && (ep == CDC_OUT_EP || ep == (CDC_CMD_EP & 0x7f))) { recipient = USBD_MODE_CDC; + cdc = usbd->cdc; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if ((mode & USBD_MODE_CDC2) && (ep == CDC2_OUT_EP || ep == (CDC2_CMD_EP & 0x7f))) { + recipient = USBD_MODE_CDC; + cdc = usbd->cdc2; + #endif } else if ((mode & USBD_MODE_MSC) && ep == MSC_OUT_EP) { recipient = USBD_MODE_MSC; } else if ((mode & USBD_MODE_HID) && ep == usbd->hid->out_ep) { @@ -869,18 +932,18 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp if (req->wLength) { if (req->bmRequest & 0x80) { // device-to-host request - usbd_cdc_control(usbd->cdc, req->bRequest, (uint8_t*)usbd->cdc->ctl_packet_buf, req->wLength); - USBD_CtlSendData(pdev, (uint8_t*)usbd->cdc->ctl_packet_buf, req->wLength); + usbd_cdc_control(cdc, req->bRequest, (uint8_t*)cdc->ctl_packet_buf, req->wLength); + USBD_CtlSendData(pdev, (uint8_t*)cdc->ctl_packet_buf, req->wLength); } else { // host-to-device request - usbd->cdc->cur_request = req->bRequest; - usbd->cdc->cur_length = req->wLength; - USBD_CtlPrepareRx(pdev, (uint8_t*)usbd->cdc->ctl_packet_buf, req->wLength); + cdc->cur_request = req->bRequest; + cdc->cur_length = req->wLength; + USBD_CtlPrepareRx(pdev, (uint8_t*)cdc->ctl_packet_buf, req->wLength); } } else { // Not a Data request // Transfer the command to the interface layer - return usbd_cdc_control(usbd->cdc, req->bRequest, NULL, req->wValue); + return usbd_cdc_control(cdc, req->bRequest, NULL, req->wValue); } } else if (recipient == USBD_MODE_MSC) { switch (req->bRequest) { @@ -1002,6 +1065,12 @@ static uint8_t USBD_CDC_MSC_HID_EP0_RxReady(USBD_HandleTypeDef *pdev) { usbd_cdc_control(usbd->cdc, usbd->cdc->cur_request, (uint8_t*)usbd->cdc->ctl_packet_buf, usbd->cdc->cur_length); usbd->cdc->cur_request = 0xff; } + #if MICROPY_HW_USB_ENABLE_CDC2 + if (usbd->cdc2 != NULL && usbd->cdc2->cur_request != 0xff) { + usbd_cdc_control(usbd->cdc2, usbd->cdc2->cur_request, (uint8_t*)usbd->cdc2->ctl_packet_buf, usbd->cdc2->cur_length); + usbd->cdc2->cur_request = 0xff; + } + #endif return USBD_OK; } @@ -1011,6 +1080,11 @@ static uint8_t USBD_CDC_MSC_HID_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) if ((usbd->usbd_mode & USBD_MODE_CDC) && (epnum == (CDC_IN_EP & 0x7f) || epnum == (CDC_CMD_EP & 0x7f))) { usbd->cdc->tx_in_progress = 0; return USBD_OK; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if ((usbd->usbd_mode & USBD_MODE_CDC2) && (epnum == (CDC2_IN_EP & 0x7f) || epnum == (CDC2_CMD_EP & 0x7f))) { + usbd->cdc2->tx_in_progress = 0; + return USBD_OK; + #endif } else if ((usbd->usbd_mode & USBD_MODE_MSC) && epnum == (MSC_IN_EP & 0x7f)) { MSC_BOT_DataIn(pdev, epnum); return USBD_OK; @@ -1035,6 +1109,12 @@ static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) usbd_cdc_receive(usbd->cdc, len); return USBD_OK; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if ((usbd->usbd_mode & USBD_MODE_CDC2) && epnum == (CDC2_OUT_EP & 0x7f)) { + size_t len = USBD_LL_GetRxDataSize(pdev, epnum); + usbd_cdc_receive(usbd->cdc2, len); + return USBD_OK; + #endif } else if ((usbd->usbd_mode & USBD_MODE_MSC) && epnum == (MSC_OUT_EP & 0x7f)) { MSC_BOT_DataOut(pdev, epnum); return USBD_OK; @@ -1046,11 +1126,31 @@ static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) return USBD_OK; } +#if USBD_SUPPORT_HS_MODE +static void usbd_cdc_desc_config_max_packet(USBD_HandleTypeDef *pdev, uint8_t *cdc_desc) { + uint32_t mp = usbd_cdc_max_packet(pdev); + cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_LO] = LOBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_HI] = HIBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_LO] = LOBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_HI] = HIBYTE(mp); + uint8_t interval; // polling interval in frames of 1ms + if (pdev->dev_speed == USBD_SPEED_HIGH) { + interval = 0x09; + } else { + interval = 0x20; + } + cdc_desc[CDC_DESC_OFFSET_INTR_INTERVAL] = interval; +} +#endif + static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t *length) { usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; #if USBD_SUPPORT_HS_MODE uint8_t *cdc_desc = NULL; + #if MICROPY_HW_USB_ENABLE_CDC2 + uint8_t *cdc2_desc = NULL; + #endif uint8_t *msc_desc = NULL; switch (usbd->usbd_mode) { case USBD_MODE_MSC: @@ -1062,6 +1162,14 @@ static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t * msc_desc = usbd->usbd_config_desc + CDC_MSC_TEMPLATE_MSC_DESC_OFFSET; break; + #if MICROPY_HW_USB_ENABLE_CDC2 + case USBD_MODE_CDC2_MSC: + cdc_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_CDC_DESC_OFFSET; + cdc2_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_CDC2_DESC_OFFSET; + msc_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_MSC_DESC_OFFSET; + break; + #endif + case USBD_MODE_CDC_HID: cdc_desc = usbd->usbd_config_desc + CDC_HID_TEMPLATE_CDC_DESC_OFFSET; break; @@ -1073,20 +1181,15 @@ static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t * // configure CDC descriptors, if needed if (cdc_desc != NULL) { - uint32_t mp = usbd_cdc_max_packet(pdev); - cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_LO] = LOBYTE(mp); - cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_HI] = HIBYTE(mp); - cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_LO] = LOBYTE(mp); - cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_HI] = HIBYTE(mp); - uint8_t interval; // polling interval in frames of 1ms - if (pdev->dev_speed == USBD_SPEED_HIGH) { - interval = 0x09; - } else { - interval = 0x20; - } - cdc_desc[CDC_DESC_OFFSET_INTR_INTERVAL] = interval; + usbd_cdc_desc_config_max_packet(pdev, cdc_desc); } + #if MICROPY_HW_USB_ENABLE_CDC2 + if (cdc2_desc != NULL) { + usbd_cdc_desc_config_max_packet(pdev, cdc2_desc); + } + #endif + if (msc_desc != NULL) { uint32_t mp = usbd_msc_max_packet(pdev); msc_desc[13] = LOBYTE(mp); @@ -1135,7 +1238,7 @@ uint8_t USBD_CDC_ReceivePacket(usbd_cdc_state_t *cdc, uint8_t *buf) { #endif // Prepare Out endpoint to receive next packet - USBD_LL_PrepareReceive(cdc->usbd->pdev, CDC_OUT_EP, buf, usbd_cdc_max_packet(cdc->usbd->pdev)); + USBD_LL_PrepareReceive(cdc->usbd->pdev, cdc->out_ep, buf, usbd_cdc_max_packet(cdc->usbd->pdev)); return USBD_OK; } From e6b66f1092472b2d371aab90ad2f556bab4ad8c0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 15 May 2018 00:18:03 +1000 Subject: [PATCH 655/828] stm32/usb: Initialise cdc variable to prevent compiler warnings. Some compilers cannot deduce that cdc will always be written before being used. --- ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c index d0b922d761..b75e5d0c54 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -880,7 +880,7 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp // Work out the recipient of the setup request uint8_t mode = usbd->usbd_mode; uint8_t recipient = 0; - usbd_cdc_state_t *cdc; + usbd_cdc_state_t *cdc = NULL; switch (req->bmRequest & USB_REQ_RECIPIENT_MASK) { case USB_REQ_RECIPIENT_INTERFACE: { uint16_t iface = req->wIndex; From c97607db5ccc03afbccacf853f2cd06305c28251 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 15 May 2018 11:17:28 +1000 Subject: [PATCH 656/828] py/nlrx86: Use naked attribute on nlr_push for gcc 8.0 and higher. gcc 8.0 supports the naked attribute for x86 systems so it can now be used here. And in fact it is necessary to use this for nlr_push because gcc 8.0 no longer generates a prelude for this function (even without the naked attribute). --- py/nlrx86.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/py/nlrx86.c b/py/nlrx86.c index 23882cc307..59b97d8ee6 100644 --- a/py/nlrx86.c +++ b/py/nlrx86.c @@ -39,15 +39,29 @@ unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail"); __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); #endif +#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 8 +// Since gcc 8.0 the naked attribute is supported +#define USE_NAKED (1) +#define UNDO_PRELUDE (0) +#elif defined(__ZEPHYR__) || defined(__ANDROID__) +// Zephyr and Android use a different calling convention by default +#define USE_NAKED (0) +#define UNDO_PRELUDE (0) +#else +#define USE_NAKED (0) +#define UNDO_PRELUDE (1) +#endif + +#if USE_NAKED +__attribute__((naked)) +#endif unsigned int nlr_push(nlr_buf_t *nlr) { + #if !USE_NAKED (void)nlr; + #endif __asm volatile ( - // Check for Zephyr, which uses a different calling convention - // by default. - // TODE: Better support for various x86 calling conventions - // (unfortunately, __attribute__((naked)) is not supported on x86). - #if !(defined(__ZEPHYR__) || defined(__ANDROID__)) + #if UNDO_PRELUDE "pop %ebp \n" // undo function's prelude #endif "mov 4(%esp), %edx \n" // load nlr_buf @@ -61,7 +75,9 @@ unsigned int nlr_push(nlr_buf_t *nlr) { "jmp nlr_push_tail \n" // do the rest in C ); + #if !USE_NAKED return 0; // needed to silence compiler warning + #endif } NORETURN void nlr_jump(void *val) { From cdaace1fdf6b0788bbf80ea316c478ddf07a057e Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 15 May 2018 11:50:37 +1000 Subject: [PATCH 657/828] esp32/modnetwork: Fix STA/AP activate/deactivate for new IDF API. WIFI_MODE_NULL is no longer supported by the ESP IDF, instead one must use esp_wifi_start/esp_wifi_stop. --- ports/esp32/modnetwork.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index f3be999a7a..8a2e266c62 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -118,6 +118,9 @@ STATIC const wlan_if_obj_t wlan_ap_obj = {{&wlan_if_type}, WIFI_IF_AP}; //static wifi_config_t wifi_ap_config = {{{0}}}; static wifi_config_t wifi_sta_config = {{{0}}}; +// Set to "true" if esp_wifi_start() was called +static bool wifi_started = false; + // Set to "true" if the STA interface is requested to be connected by the // user, used for automatic reassociation. static bool wifi_sta_connected = false; @@ -197,9 +200,6 @@ STATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args) { ESP_EXCEPTIONS( esp_wifi_init(&cfg) ); ESP_EXCEPTIONS( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); ESP_LOGD("modnetwork", "Initialized"); - ESP_EXCEPTIONS( esp_wifi_set_mode(0) ); - ESP_EXCEPTIONS( esp_wifi_start() ); - ESP_LOGD("modnetwork", "Started"); initialized = 1; } @@ -233,16 +233,32 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_initialize_obj, esp_initialize); #endif STATIC mp_obj_t esp_active(size_t n_args, const mp_obj_t *args) { - wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + wifi_mode_t mode; - ESP_EXCEPTIONS( esp_wifi_get_mode(&mode) ); + if (!wifi_started) { + mode = WIFI_MODE_NULL; + } else { + ESP_EXCEPTIONS(esp_wifi_get_mode(&mode)); + } + int bit = (self->if_id == WIFI_IF_STA) ? WIFI_MODE_STA : WIFI_MODE_AP; if (n_args > 1) { - bool active = mp_obj_is_true(args[1]); - mode = active ? (mode | bit) : (mode & ~bit); - ESP_EXCEPTIONS( esp_wifi_set_mode(mode) ); + bool active = mp_obj_is_true(args[1]); + mode = active ? (mode | bit) : (mode & ~bit); + if (mode == WIFI_MODE_NULL) { + if (wifi_started) { + ESP_EXCEPTIONS(esp_wifi_stop()); + wifi_started = false; + } + } else { + ESP_EXCEPTIONS(esp_wifi_set_mode(mode)); + if (!wifi_started) { + ESP_EXCEPTIONS(esp_wifi_start()); + wifi_started = true; + } + } } return (mode & bit) ? mp_const_true : mp_const_false; From b9ff46f1ed5e1468551890ce64a842c77c059ef6 Mon Sep 17 00:00:00 2001 From: Ryan Shaw Date: Tue, 15 May 2018 12:46:58 +1000 Subject: [PATCH 658/828] stm32: Enable UART7/8 on F4 series that have these peripherals. --- ports/stm32/boards/startup_stm32f4.s | 8 ++++++++ ports/stm32/boards/stm32f439_af.csv | 12 ++++++------ ports/stm32/mpconfigboard_common.h | 4 ++++ ports/stm32/stm32_it.c | 4 ++-- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/ports/stm32/boards/startup_stm32f4.s b/ports/stm32/boards/startup_stm32f4.s index e46a93b71a..3e29a79a56 100644 --- a/ports/stm32/boards/startup_stm32f4.s +++ b/ports/stm32/boards/startup_stm32f4.s @@ -241,6 +241,8 @@ g_pfnVectors: .word 0 /* CRYP crypto */ .word HASH_RNG_IRQHandler /* Hash and Rng */ .word FPU_IRQHandler /* FPU */ + .word UART7_IRQHandler /* UART7 */ + .word UART8_IRQHandler /* UART8 */ /******************************************************************************* * @@ -519,4 +521,10 @@ g_pfnVectors: .weak FPU_IRQHandler .thumb_set FPU_IRQHandler,Default_Handler + .weak UART7_IRQHandler + .thumb_set UART7_IRQHandler,Default_Handler + + .weak UART8_IRQHandler + .thumb_set UART8_IRQHandler,Default_Handler + /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/boards/stm32f439_af.csv b/ports/stm32/boards/stm32f439_af.csv index dc36415024..4fc1f1116c 100644 --- a/ports/stm32/boards/stm32f439_af.csv +++ b/ports/stm32/boards/stm32f439_af.csv @@ -64,15 +64,15 @@ PortD,PD12,,,TIM4_CH1,,,,,USART3_RTS,,,,,FMC_A17,,,EVENTOUT, PortD,PD13,,,TIM4_CH2,,,,,,,,,,FMC_A18,,,EVENTOUT, PortD,PD14,,,TIM4_CH3,,,,,,,,,,FMC_D0,,,EVENTOUT, PortD,PD15,,,TIM4_CH4,,,,,,,,,,FMC_D1,,,EVENTOUT, -PortE,PE0,,,TIM4_ETR,,,,,,UART8_Rx,,,,FMC_NBL0,DCMI_D2,,EVENTOUT, -PortE,PE1,,,,,,,,,UART8_Tx,,,,FMC_NBL1,DCMI_D3,,EVENTOUT, +PortE,PE0,,,TIM4_ETR,,,,,,UART8_RX,,,,FMC_NBL0,DCMI_D2,,EVENTOUT, +PortE,PE1,,,,,,,,,UART8_TX,,,,FMC_NBL1,DCMI_D3,,EVENTOUT, PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,,,ETH_MII_TXD3,FMC_A23,,,EVENTOUT, PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT, PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT, PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT, PortE,PE6,TRACED3,,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,,,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT, -PortE,PE7,,TIM1_ETR,,,,,,,UART7_Rx,,,,FMC_D4,,,EVENTOUT, -PortE,PE8,,TIM1_CH1N,,,,,,,UART7_Tx,,,,FMC_D5,,,EVENTOUT, +PortE,PE7,,TIM1_ETR,,,,,,,UART7_RX,,,,FMC_D4,,,EVENTOUT, +PortE,PE8,,TIM1_CH1N,,,,,,,UART7_TX,,,,FMC_D5,,,EVENTOUT, PortE,PE9,,TIM1_CH1,,,,,,,,,,,FMC_D6,,,EVENTOUT, PortE,PE10,,TIM1_CH2N,,,,,,,,,,,FMC_D7,,,EVENTOUT, PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,SPI3_NSS,,,,,,FMC_D8,,LCD_G3,EVENTOUT, @@ -86,8 +86,8 @@ PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT, PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN9 PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN14 PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN15 -PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_Rx,,,,FMC_NIORD,,,EVENTOUT,ADC3_IN4 -PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_Tx,,,,FMC_NREG,,,EVENTOUT,ADC3_IN5 +PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_RX,,,,FMC_NIORD,,,EVENTOUT,ADC3_IN4 +PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_TX,,,,FMC_NREG,,,EVENTOUT,ADC3_IN5 PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,,TIM13_CH1,,,FMC_NIOWR,,,EVENTOUT,ADC3_IN6 PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,,TIM14_CH1,,,FMC_CD,,,EVENTOUT,ADC3_IN7 PortF,PF10,,,,,,,,,,,,,FMC_INTR,DCMI_D11,LCD_DE,EVENTOUT,ADC3_IN8 diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index a33b8d042d..7449a68956 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -116,7 +116,11 @@ #define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7a10) #define PYB_EXTI_NUM_VECTORS (23) #define MICROPY_HW_MAX_TIMER (14) +#ifdef UART8 +#define MICROPY_HW_MAX_UART (8) +#else #define MICROPY_HW_MAX_UART (6) +#endif // Configuration for STM32F7 series #elif defined(STM32F7) diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index a77802bfa4..d2cd0788a4 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -720,7 +720,7 @@ void USART6_IRQHandler(void) { IRQ_EXIT(USART6_IRQn); } -#if defined(MICROPY_HW_UART7_TX) +#if defined(UART8) void UART7_IRQHandler(void) { IRQ_ENTER(UART7_IRQn); uart_irq_handler(7); @@ -728,7 +728,7 @@ void UART7_IRQHandler(void) { } #endif -#if defined(MICROPY_HW_UART8_TX) +#if defined(UART8) void UART8_IRQHandler(void) { IRQ_ENTER(UART8_IRQn); uart_irq_handler(8); From 1b7487e519c2e2a66f2f5a45ebd238d0773ca3d3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 16 May 2018 12:33:39 +1000 Subject: [PATCH 659/828] py/vm: Adjust #if logic for gil_divisor so braces are balanced. Having balanced braces { and } makes it easier to navigate the function. --- py/vm.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/py/vm.c b/py/vm.c index 8abe65e43b..b88cfd8d37 100644 --- a/py/vm.c +++ b/py/vm.c @@ -1322,11 +1322,12 @@ pending_exception_check: #if MICROPY_PY_THREAD_GIL #if MICROPY_PY_THREAD_GIL_VM_DIVISOR - if (--gil_divisor == 0) { - gil_divisor = MICROPY_PY_THREAD_GIL_VM_DIVISOR; - #else - { + if (--gil_divisor == 0) #endif + { + #if MICROPY_PY_THREAD_GIL_VM_DIVISOR + gil_divisor = MICROPY_PY_THREAD_GIL_VM_DIVISOR; + #endif #if MICROPY_ENABLE_SCHEDULER // can only switch threads if the scheduler is unlocked if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) From a883fe12d95953e9aa705f0050da1b61ae54ec8d Mon Sep 17 00:00:00 2001 From: Tom Collins Date: Wed, 16 May 2018 17:08:34 -0700 Subject: [PATCH 660/828] py/objfun: Fix variable name in DECODE_CODESTATE_SIZE() macro. This patch fixes the macro so you can pass any name in, and the macro will make more sense if you're reading it on its own. It worked previously because n_state is always passed in as n_state_out_var. --- py/objfun.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/py/objfun.c b/py/objfun.c index e6d33d287c..8c51d92e06 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -204,10 +204,11 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) { n_state_out_var = mp_decode_uint_value(bytecode); \ size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(bytecode)); \ \ - n_state += VM_DETECT_STACK_OVERFLOW; \ + n_state_out_var += VM_DETECT_STACK_OVERFLOW; \ \ /* state size in bytes */ \ - state_size_out_var = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t); \ + state_size_out_var = n_state_out_var * sizeof(mp_obj_t) \ + + n_exc_stack * sizeof(mp_exc_stack_t); \ } #define INIT_CODESTATE(code_state, _fun_bc, n_args, n_kw, args) \ From 9c2044717c8852105df25746a8a7b873fbfc3609 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 17 May 2018 12:58:34 +1000 Subject: [PATCH 661/828] extmod/modlwip: Update to work with lwIP v2.0. lwIP v2.0.3 has been tested with this lwip module and it works very well. --- extmod/modlwip.c | 56 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 3aa0237073..19766c0c8a 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -38,13 +38,18 @@ #include "lib/netutils/netutils.h" #include "lwip/init.h" -#include "lwip/timers.h" #include "lwip/tcp.h" #include "lwip/udp.h" //#include "lwip/raw.h" #include "lwip/dns.h" -#include "lwip/tcp_impl.h" #include "lwip/igmp.h" +#if LWIP_VERSION_MAJOR < 2 +#include "lwip/timers.h" +#include "lwip/tcp_impl.h" +#else +#include "lwip/timeouts.h" +#include "lwip/priv/tcp_priv.h" +#endif #if 0 // print debugging info #define DEBUG_printf DEBUG_printf @@ -171,11 +176,16 @@ STATIC const mp_obj_type_t lwip_slip_type = { // Table to convert lwIP err_t codes to socket errno codes, from the lwIP // socket API. +// lwIP 2 changed LWIP_VERSION and it can no longer be used in macros, +// so we define our own equivalent version that can. +#define LWIP_VERSION_MACRO (LWIP_VERSION_MAJOR << 24 | LWIP_VERSION_MINOR << 16 \ + | LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC) + // Extension to lwIP error codes #define _ERR_BADF -16 // TODO: We just know that change happened somewhere between 1.4.0 and 1.4.1, // investigate in more detail. -#if LWIP_VERSION < 0x01040100 +#if LWIP_VERSION_MACRO < 0x01040100 static const int error_lookup_table[] = { 0, /* ERR_OK 0 No error, everything OK. */ MP_ENOMEM, /* ERR_MEM -1 Out of memory error. */ @@ -196,7 +206,7 @@ static const int error_lookup_table[] = { MP_EALREADY, /* ERR_ISCONN -15 Already connected. */ MP_EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */ }; -#else +#elif LWIP_VERSION_MACRO < 0x02000000 static const int error_lookup_table[] = { 0, /* ERR_OK 0 No error, everything OK. */ MP_ENOMEM, /* ERR_MEM -1 Out of memory error. */ @@ -217,6 +227,30 @@ static const int error_lookup_table[] = { -1, /* ERR_IF -15 Low-level netif error */ MP_EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */ }; +#else +// Matches lwIP 2.0.3 +#undef _ERR_BADF +#define _ERR_BADF -17 +static const int error_lookup_table[] = { + 0, /* ERR_OK 0 No error, everything OK */ + MP_ENOMEM, /* ERR_MEM -1 Out of memory error */ + MP_ENOBUFS, /* ERR_BUF -2 Buffer error */ + MP_EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ + MP_EHOSTUNREACH, /* ERR_RTE -4 Routing problem */ + MP_EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ + MP_EINVAL, /* ERR_VAL -6 Illegal value */ + MP_EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block */ + MP_EADDRINUSE, /* ERR_USE -8 Address in use */ + MP_EALREADY, /* ERR_ALREADY -9 Already connecting */ + MP_EALREADY, /* ERR_ISCONN -10 Conn already established */ + MP_ENOTCONN, /* ERR_CONN -11 Not connected */ + -1, /* ERR_IF -12 Low-level netif error */ + MP_ECONNABORTED, /* ERR_ABRT -13 Connection aborted */ + MP_ECONNRESET, /* ERR_RST -14 Connection reset */ + MP_ENOTCONN, /* ERR_CLSD -15 Connection closed */ + MP_EIO, /* ERR_ARG -16 Illegal argument. */ + MP_EBADF, /* _ERR_BADF -17 Closed socket (null pcb) */ +}; #endif /*******************************************************************************/ @@ -276,7 +310,12 @@ static inline void exec_user_callback(lwip_socket_obj_t *socket) { // Callback for incoming UDP packets. We simply stash the packet and the source address, // in case we need it for recvfrom. -STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port) { +#if LWIP_VERSION_MAJOR < 2 +STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port) +#else +STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +#endif +{ lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg; if (socket->incoming.pbuf != NULL) { @@ -1287,7 +1326,12 @@ typedef struct _getaddrinfo_state_t { } getaddrinfo_state_t; // Callback for incoming DNS requests. -STATIC void lwip_getaddrinfo_cb(const char *name, ip_addr_t *ipaddr, void *arg) { +#if LWIP_VERSION_MAJOR < 2 +STATIC void lwip_getaddrinfo_cb(const char *name, ip_addr_t *ipaddr, void *arg) +#else +STATIC void lwip_getaddrinfo_cb(const char *name, const ip_addr_t *ipaddr, void *arg) +#endif +{ getaddrinfo_state_t *state = arg; if (ipaddr != NULL) { state->status = 1; From 7d7b9cd5dffdecf1e4176a7f3ddb84e7e3bc7318 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 17 May 2018 13:11:31 +1000 Subject: [PATCH 662/828] lib/lwip: Update lwIP to v2.0.3, tag STABLE-2_0_3_RELEASE. --- lib/lwip | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/lwip b/lib/lwip index 5b8b5d459e..92f23d6ca0 160000 --- a/lib/lwip +++ b/lib/lwip @@ -1 +1 @@ -Subproject commit 5b8b5d459e7dd890724515bbfad86c705234f9ec +Subproject commit 92f23d6ca0971a32f2085b9480e738d34174417b From 94a79f340dd86ce698f8f55c6c6111f21256b91f Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 17 May 2018 13:27:18 +1000 Subject: [PATCH 663/828] esp8266/mpconfigport.h: Add some weak links to common Python modules. To make it easier/simpler to write code that can run under both CPython and on an ESP8266 board. --- ports/esp8266/mpconfigport.h | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index fc992a4b1b..8de28eb96e 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -171,12 +171,21 @@ extern const struct _mp_obj_module_t mp_module_onewire; { MP_ROM_QSTR(MP_QSTR__onewire), MP_ROM_PTR(&mp_module_onewire) }, \ #define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ - { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&utime_module) }, \ - { MP_ROM_QSTR(MP_QSTR_os), MP_ROM_PTR(&uos_module) }, \ - { MP_ROM_QSTR(MP_QSTR_json), MP_ROM_PTR(&mp_module_ujson) }, \ + { MP_ROM_QSTR(MP_QSTR_binascii), MP_ROM_PTR(&mp_module_ubinascii) }, \ + { MP_ROM_QSTR(MP_QSTR_collections), MP_ROM_PTR(&mp_module_collections) }, \ { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_module_uerrno) }, \ + { MP_ROM_QSTR(MP_QSTR_hashlib), MP_ROM_PTR(&mp_module_uhashlib) }, \ + { MP_ROM_QSTR(MP_QSTR_io), MP_ROM_PTR(&mp_module_io) }, \ + { MP_ROM_QSTR(MP_QSTR_json), MP_ROM_PTR(&mp_module_ujson) }, \ + { MP_ROM_QSTR(MP_QSTR_os), MP_ROM_PTR(&uos_module) }, \ + { MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&mp_module_urandom) }, \ + { MP_ROM_QSTR(MP_QSTR_re), MP_ROM_PTR(&mp_module_ure) }, \ { MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mp_module_uselect) }, \ { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_lwip) }, \ + { MP_ROM_QSTR(MP_QSTR_ssl), MP_ROM_PTR(&mp_module_ussl) }, \ + { MP_ROM_QSTR(MP_QSTR_struct), MP_ROM_PTR(&mp_module_ustruct) }, \ + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&utime_module) }, \ + { MP_ROM_QSTR(MP_QSTR_zlib), MP_ROM_PTR(&mp_module_uzlib) }, \ #define MP_STATE_PORT MP_STATE_VM From f8a5cd24d898f06f742839e0629016e704affadc Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 17 May 2018 22:11:22 +1000 Subject: [PATCH 664/828] esp8266/modnetwork: Return empty str for hostname if STA is inactive. Instead of crashing due to NULL pointer dereference. Fixes issue #3341. --- ports/esp8266/modnetwork.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ports/esp8266/modnetwork.c b/ports/esp8266/modnetwork.c index dcc64d40ff..7ececaf95c 100644 --- a/ports/esp8266/modnetwork.c +++ b/ports/esp8266/modnetwork.c @@ -443,7 +443,11 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs case MP_QSTR_dhcp_hostname: { req_if = STATION_IF; char* s = wifi_station_get_hostname(); - val = mp_obj_new_str(s, strlen(s)); + if (s == NULL) { + val = MP_OBJ_NEW_QSTR(MP_QSTR_); + } else { + val = mp_obj_new_str(s, strlen(s)); + } break; } default: From dd13065843060b8351c80ba62a32a24713fd27b1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 17 May 2018 22:12:24 +1000 Subject: [PATCH 665/828] esp8266/modnetwork: Raise ValueError when getting invalid WLAN id. Instead of crashing due to out-of-bounds array access. Fixes #3348. --- ports/esp8266/modnetwork.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/esp8266/modnetwork.c b/ports/esp8266/modnetwork.c index 7ececaf95c..c7f3397c44 100644 --- a/ports/esp8266/modnetwork.c +++ b/ports/esp8266/modnetwork.c @@ -65,6 +65,9 @@ STATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args) { int idx = 0; if (n_args > 0) { idx = mp_obj_get_int(args[0]); + if (idx < 0 || idx >= sizeof(wlan_objs)) { + mp_raise_ValueError(NULL); + } } return MP_OBJ_FROM_PTR(&wlan_objs[idx]); } From 1e2a6a84a263e069d7be5f27d73e7fc124413fa5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 17 May 2018 23:17:36 +1000 Subject: [PATCH 666/828] extmod/modlwip: Set POLLHUP flag for sockets that are new. This matches CPython behaviour on Linux: a socket that is new and not listening or connected is considered "hung up". Thanks to @rkojedzinszky for the initial patch, PR #3457. --- extmod/modlwip.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 19766c0c8a..7c0a20a1bf 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -723,6 +723,9 @@ STATIC mp_obj_t lwip_socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) { socket->pcb.tcp = new_pcb; tcp_accept(new_pcb, _lwip_tcp_accept); + // Socket is no longer considered "new" for purposes of polling + socket->state = STATE_CONNECTING; + return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_listen_obj, lwip_socket_listen); @@ -1176,7 +1179,10 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ ret |= MP_STREAM_POLL_WR; } - if (socket->state == STATE_PEER_CLOSED) { + if (socket->state == STATE_NEW) { + // New sockets are not connected so set HUP + ret |= flags & MP_STREAM_POLL_HUP; + } else if (socket->state == STATE_PEER_CLOSED) { // Peer-closed socket is both readable and writable: read will // return EOF, write - error. Without this poll will hang on a // socket which was closed by peer. From 58331e3c28e41ad7e3c3dd7dabf6d508a8bfe1cb Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 17 May 2018 23:37:12 +1000 Subject: [PATCH 667/828] esp8266/modmachine: Allow I2C and SPI to be configured out of the build. I2C costs about 3000 bytes of code, and SPI costs about 4400 bytes. --- ports/esp8266/machine_hspi.c | 4 ++++ ports/esp8266/modmachine.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/ports/esp8266/machine_hspi.c b/ports/esp8266/machine_hspi.c index ff77282911..07770c8c89 100644 --- a/ports/esp8266/machine_hspi.c +++ b/ports/esp8266/machine_hspi.c @@ -39,6 +39,8 @@ #include "modmachine.h" #include "hspi.h" +#if MICROPY_PY_MACHINE_SPI + typedef struct _machine_hspi_obj_t { mp_obj_base_t base; uint32_t baudrate; @@ -180,3 +182,5 @@ const mp_obj_type_t machine_hspi_type = { .protocol = &machine_hspi_p, .locals_dict = (mp_obj_dict_t*)&mp_machine_spi_locals_dict, }; + +#endif // MICROPY_PY_MACHINE_SPI diff --git a/ports/esp8266/modmachine.c b/ports/esp8266/modmachine.c index 99286848e2..7e5f6714bf 100644 --- a/ports/esp8266/modmachine.c +++ b/ports/esp8266/modmachine.c @@ -255,8 +255,12 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&pyb_pwm_type) }, { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) }, + #if MICROPY_PY_MACHINE_I2C { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, + #endif + #if MICROPY_PY_MACHINE_SPI { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_hspi_type) }, + #endif // wake abilities { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) }, From 46ce395130305ce3299ae0dfd42502d29837c39f Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 18 May 2018 11:44:26 +1000 Subject: [PATCH 668/828] py/vm: Use enum names instead of magic numbers in multi-opcode dispatch. --- py/vm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/py/vm.c b/py/vm.c index b88cfd8d37..52e15ae337 100644 --- a/py/vm.c +++ b/py/vm.c @@ -1270,10 +1270,10 @@ yield: } else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) { fastn[MP_BC_STORE_FAST_MULTI - (mp_int_t)ip[-1]] = POP(); DISPATCH(); - } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + 7) { + } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE) { SET_TOP(mp_unary_op(ip[-1] - MP_BC_UNARY_OP_MULTI, TOP())); DISPATCH(); - } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + 36) { + } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE) { mp_obj_t rhs = POP(); mp_obj_t lhs = TOP(); SET_TOP(mp_binary_op(ip[-1] - MP_BC_BINARY_OP_MULTI, lhs, rhs)); From 869024dd6e62905b7e1069b547856a769b3b24ba Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 18 May 2018 11:47:03 +1000 Subject: [PATCH 669/828] py/vm: Improve performance of opcode dispatch when using switch stmt. Before this patch, when using the switch statement for dispatch in the VM (not computed goto) a pending exception check was done after each opcode. This is not necessary and this patch makes the pending exception check only happen when explicitly requested by certain opcodes, like jump. This improves performance of the VM by about 2.5% when using the switch. --- py/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/vm.c b/py/vm.c index 52e15ae337..d24a024d54 100644 --- a/py/vm.c +++ b/py/vm.c @@ -136,7 +136,7 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp #define ENTRY(op) entry_##op #define ENTRY_DEFAULT entry_default #else - #define DISPATCH() break + #define DISPATCH() goto dispatch_loop #define DISPATCH_WITH_PEND_EXC_CHECK() goto pending_exception_check #define ENTRY(op) case op #define ENTRY_DEFAULT default From 3e6ab82179f7b9a1df915f4bd0d6e48a454d942c Mon Sep 17 00:00:00 2001 From: Li Weiwei Date: Fri, 18 May 2018 11:15:53 +0800 Subject: [PATCH 670/828] py/repl: Fix handling of unmatched brackets and unfinished quotes. Before this patch: >>> print(') ... ') Traceback (most recent call last): File "", line 1 SyntaxError: invalid syntax After this patch: >>> print(') Traceback (most recent call last): File "", line 1 SyntaxError: invalid syntax This matches CPython and prevents getting stuck in REPL continuation when a 1-quote is unmatched. --- py/repl.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/py/repl.c b/py/repl.c index 5dce8bbb7d..da0fefb3a9 100644 --- a/py/repl.c +++ b/py/repl.c @@ -106,8 +106,13 @@ bool mp_repl_continue_with_input(const char *input) { } } - // continue if unmatched brackets or quotes - if (n_paren > 0 || n_brack > 0 || n_brace > 0 || in_quote == Q_3_SINGLE || in_quote == Q_3_DOUBLE) { + // continue if unmatched 3-quotes + if (in_quote == Q_3_SINGLE || in_quote == Q_3_DOUBLE) { + return true; + } + + // continue if unmatched brackets, but only if not in a 1-quote + if ((n_paren > 0 || n_brack > 0 || n_brace > 0) && in_quote == Q_NONE) { return true; } From 708cdb627648428e0c27c7f644a776e1defe7349 Mon Sep 17 00:00:00 2001 From: Tobias Badertscher Date: Fri, 18 May 2018 09:03:53 +0200 Subject: [PATCH 671/828] stm32: Add support for STM32L496 MCU. --- ports/stm32/adc.c | 3 +- ports/stm32/boards/startup_stm32l4.s | 123 ++++++++++++++++----------- ports/stm32/boards/stm32l476xe.ld | 3 + ports/stm32/boards/stm32l476xg.ld | 5 +- ports/stm32/flashbdev.c | 8 +- ports/stm32/mphalport.c | 2 +- ports/stm32/system_stm32.c | 6 +- 7 files changed, 92 insertions(+), 58 deletions(-) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index efc89a7780..773cccd40e 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -118,7 +118,8 @@ #define VBAT_DIV (4) #elif defined(STM32H743xx) #define VBAT_DIV (4) -#elif defined(STM32L475xx) || defined(STM32L476xx) +#elif defined(STM32L475xx) || defined(STM32L476xx) || \ + defined(STM32L496xx) #define VBAT_DIV (3) #else #error Unsupported processor diff --git a/ports/stm32/boards/startup_stm32l4.s b/ports/stm32/boards/startup_stm32l4.s index 83af6d09ad..3225723ff5 100644 --- a/ports/stm32/boards/startup_stm32l4.s +++ b/ports/stm32/boards/startup_stm32l4.s @@ -1,44 +1,33 @@ /** ****************************************************************************** - * @file startup_stm32.S + * @file startup_stm32l496xx.s * @author MCD Application Team - * @version V2.0.0 - * @date 18-February-2014 - * @brief STM32Fxxxxx Devices vector table for Atollic TrueSTUDIO toolchain. + * @brief STM32L496xx devices vector table GCC toolchain. * This module performs: * - Set the initial SP * - Set the initial PC == Reset_Handler, - * - Set the vector table entries with the exceptions ISR address + * - Set the vector table entries with the exceptions ISR address, * - Branches to main in the C library (which eventually * calls main()). - * After Reset the Cortex-M4/M7 processor is in Thread mode, + * After Reset the Cortex-M4 processor is in Thread mode, * priority is Privileged, and the Stack is set to Main. + * Taken from STM32L4 template code for stm32l496 in STM32Cube_FW_L4_V1.11.0 ****************************************************************************** * @attention * - *

© COPYRIGHT 2014 STMicroelectronics

+ *

© COPYRIGHT 2017 STMicroelectronics

* - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * ****************************************************************************** */ @@ -64,6 +53,7 @@ defined in linker script */ .word _ebss /* stack used for SystemInit_ExtMemCtl; always internal RAM used */ +.equ BootRAM, 0xF1E0F85F /** * @brief This is the code that gets called when the processor first * starts execution following a reset event. Only the absolutely @@ -120,6 +110,7 @@ LoopFillZerobss: * @brief This is the code that gets called when the processor receives an * unexpected interrupt. This simply enters an infinite loop, preserving * the system state for examination by a debugger. + * * @param None * @retval None */ @@ -130,7 +121,7 @@ Infinite_Loop: .size Default_Handler, .-Default_Handler /****************************************************************************** * -* The minimal vector table for a Cortex M4/M7. Note that the proper constructs +* The minimal vector table for a Cortex-M4. Note that the proper constructs * must be placed on this to ensure that it ends up at physical address * 0x0000.0000. * @@ -201,7 +192,7 @@ g_pfnVectors: .word USART3_IRQHandler /* USART3 */ .word EXTI15_10_IRQHandler /* External Line[15:10]s */ .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ - .word DFSDM3_IRQHandler /* Digital filter for sigma delta modulator 3 */ + .word DFSDM1_FLT3_IRQHandler /* Digital filter 3 for sigma delta modulator */ .word TIM8_BRK_IRQHandler /* TIM8 Break */ .word TIM8_UP_IRQHandler /* TIM8 Update */ .word TIM8_TRG_COM_IRQHandler /* TIM8 Trigger and Commutation */ @@ -220,9 +211,9 @@ g_pfnVectors: .word DMA2_Channel3_IRQHandler /* DMA2 Channel 3 */ .word DMA2_Channel4_IRQHandler /* DMA2 Channel 4 */ .word DMA2_Channel5_IRQHandler /* DMA2 Channel 5 */ - .word DFSDM0_IRQHandler /* Digital filter for sigma delta modulator 0 */ - .word DFSDM1_IRQHandler /* Digital filter for sigma delta modulator 1 */ - .word DFSDM2_IRQHandler /* Digital filter for sigma delta modulator 2 */ + .word DFSDM1_FLT0_IRQHandler /* Digital filter 0 for sigma delta modulator */ + .word DFSDM1_FLT1_IRQHandler /* Digital filter 1 for sigma delta modulator */ + .word DFSDM1_FLT2_IRQHandler /* Digital filter 2 for sigma delta modulator */ .word COMP_IRQHandler /* Comporator thru EXTI line */ .word LPTIM1_IRQHandler /* Low power timer 1 */ .word LPTIM2_IRQHandler /* Low power timer 2 */ @@ -241,6 +232,16 @@ g_pfnVectors: .word 0 /* CRYP crypto */ .word RNG_IRQHandler /* Random number generator */ .word FPU_IRQHandler /* FPU */ + /* Following Handlers are only used on L496/4A6xx devices */ + .word CRS_IRQHandler /* HASH and CRS interrupt */ + .word I2C4_EV_IRQHandler /* I2C4 event interrupt */ + .word I2C4_ER_IRQHandler /* I2C4 error interrupt */ + .word DCMI_IRQHandler /* DCMI global interrupt */ + .word CAN2_TX_IRQHandler /* CAN2 TX interrupt */ + .word CAN2_RX0_IRQHandler /* CAN2 RX0 interrupt */ + .word CAN2_RX1_IRQHandler /* CAN2 RX1 interrupt */ + .word CAN2_SCE_IRQHandler /* CAN SCE interrupt */ + .word DMA2D_IRQHandler /* DMA2D global interrupt */ /******************************************************************************* * @@ -309,28 +310,28 @@ g_pfnVectors: .weak EXTI4_IRQHandler .thumb_set EXTI4_IRQHandler,Default_Handler - .weak DMA1_Channel1_IRQHandler + .weak DMA1_Channel1_IRQHandler .thumb_set DMA1_Channel1_IRQHandler,Default_Handler - .weak DMA1_Channel2_IRQHandler + .weak DMA1_Channel2_IRQHandler .thumb_set DMA1_Channel2_IRQHandler,Default_Handler - .weak DMA1_Channel3_IRQHandler + .weak DMA1_Channel3_IRQHandler .thumb_set DMA1_Channel3_IRQHandler,Default_Handler - .weak DMA1_Channel4_IRQHandler + .weak DMA1_Channel4_IRQHandler .thumb_set DMA1_Channel4_IRQHandler,Default_Handler - .weak DMA1_Channel5_IRQHandler + .weak DMA1_Channel5_IRQHandler .thumb_set DMA1_Channel5_IRQHandler,Default_Handler - .weak DMA1_Channel6_IRQHandler + .weak DMA1_Channel6_IRQHandler .thumb_set DMA1_Channel6_IRQHandler,Default_Handler - .weak DMA1_Channel7_IRQHandler + .weak DMA1_Channel7_IRQHandler .thumb_set DMA1_Channel7_IRQHandler,Default_Handler - .weak ADC1_2_IRQHandler + .weak ADC1_2_IRQHandler .thumb_set ADC1_2_IRQHandler,Default_Handler .weak CAN1_TX_IRQHandler @@ -402,8 +403,8 @@ g_pfnVectors: .weak RTC_Alarm_IRQHandler .thumb_set RTC_Alarm_IRQHandler,Default_Handler - .weak DFSDM3_IRQHandler - .thumb_set DFSDM3_IRQHandler,Default_Handler + .weak DFSDM1_FLT3_IRQHandler + .thumb_set DFSDM1_FLT3_IRQHandler,Default_Handler .weak TIM8_BRK_IRQHandler .thumb_set TIM8_BRK_IRQHandler,Default_Handler @@ -459,14 +460,14 @@ g_pfnVectors: .weak DMA2_Channel5_IRQHandler .thumb_set DMA2_Channel5_IRQHandler,Default_Handler - .weak DFSDM0_IRQHandler - .thumb_set DFSDM0_IRQHandler,Default_Handler + .weak DFSDM1_FLT0_IRQHandler + .thumb_set DFSDM1_FLT0_IRQHandler,Default_Handler - .weak DFSDM1_IRQHandler - .thumb_set DFSDM1_IRQHandler,Default_Handler + .weak DFSDM1_FLT1_IRQHandler + .thumb_set DFSDM1_FLT1_IRQHandler,Default_Handler - .weak DFSDM2_IRQHandler - .thumb_set DFSDM2_IRQHandler,Default_Handler + .weak DFSDM1_FLT2_IRQHandler + .thumb_set DFSDM1_FLT2_IRQHandler,Default_Handler .weak COMP_IRQHandler .thumb_set COMP_IRQHandler,Default_Handler @@ -519,4 +520,30 @@ g_pfnVectors: .weak FPU_IRQHandler .thumb_set FPU_IRQHandler,Default_Handler + .weak CRS_IRQHandler + .thumb_set CRS_IRQHandler,Default_Handler + + .weak I2C4_EV_IRQHandler + .thumb_set I2C4_EV_IRQHandler,Default_Handler + + .weak I2C4_ER_IRQHandler + .thumb_set I2C4_ER_IRQHandler,Default_Handler + + .weak DCMI_IRQHandler + .thumb_set DCMI_IRQHandler,Default_Handler + + .weak CAN2_TX_IRQHandler + .thumb_set CAN2_TX_IRQHandler,Default_Handler + + .weak CAN2_RX0_IRQHandler + .thumb_set CAN2_RX0_IRQHandler,Default_Handler + + .weak CAN2_RX1_IRQHandler + .thumb_set CAN2_RX1_IRQHandler,Default_Handler + + .weak CAN2_SCE_IRQHandler + .thumb_set CAN2_SCE_IRQHandler,Default_Handler + + .weak DMA2D_IRQHandler + .thumb_set DMA2D_IRQHandler,Default_Handler /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/boards/stm32l476xe.ld b/ports/stm32/boards/stm32l476xe.ld index 76f94444eb..22c4466c66 100644 --- a/ports/stm32/boards/stm32l476xe.ld +++ b/ports/stm32/boards/stm32l476xe.ld @@ -11,6 +11,7 @@ MEMORY FLASH_FS (r) : ORIGIN = 0x08060000, LENGTH = 128K /* sectors 192-255 */ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K SRAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 32K + FS_CACHE(xrw) : ORIGIN = 0x10007800, LENGTH = 2K } /* produce a link error if there is not this amount of RAM for these sections */ @@ -23,6 +24,8 @@ _minimum_heap_size = 16K; _estack = ORIGIN(RAM) + LENGTH(RAM); /* RAM extents for the garbage collector */ +_ram_fs_cache_start = ORIGIN(FS_CACHE); +_ram_fs_cache_block_size = LENGTH(FS_CACHE); _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); _heap_start = _ebss; /* heap starts just after statically allocated memory */ diff --git a/ports/stm32/boards/stm32l476xg.ld b/ports/stm32/boards/stm32l476xg.ld index 83bb23901e..40d679ac39 100644 --- a/ports/stm32/boards/stm32l476xg.ld +++ b/ports/stm32/boards/stm32l476xg.ld @@ -11,10 +11,9 @@ MEMORY FLASH_FS (r) : ORIGIN = 0x08080000, LENGTH = 512K /* sectors 256-511 */ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K SRAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 32K + FS_CACHE(xrw) : ORIGIN = 0x10007800, LENGTH = 2K } -ENTRY(Reset_Handler) - /* produce a link error if there is not this amount of RAM for these sections */ _minimum_stack_size = 2K; _minimum_heap_size = 16K; @@ -25,6 +24,8 @@ _minimum_heap_size = 16K; _estack = ORIGIN(RAM) + LENGTH(RAM); /* RAM extents for the garbage collector */ +_ram_fs_cache_start = ORIGIN(FS_CACHE); +_ram_fs_cache_block_size = LENGTH(FS_CACHE); _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); _heap_start = _ebss; /* heap starts just after statically allocated memory */ diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c index dc73223348..5ae67d1ec2 100644 --- a/ports/stm32/flashbdev.c +++ b/ports/stm32/flashbdev.c @@ -93,14 +93,16 @@ STATIC byte flash_cache_mem[0x4000] __attribute__((aligned(4))); // 16k #define FLASH_MEM_SEG1_START_ADDR (0x08020000) // sector 1 #define FLASH_MEM_SEG1_NUM_BLOCKS (256) // Sector 1: 128k / 512b = 256 blocks -#elif defined(STM32L475xx) || defined(STM32L476xx) +#elif defined(STM32L475xx) || defined(STM32L476xx) || defined(STM32L496xx) extern uint8_t _flash_fs_start; extern uint8_t _flash_fs_end; +extern uint32_t _ram_fs_cache_start[2048 / 4]; +extern uint32_t _ram_fs_cache_block_size; // The STM32L475/6 doesn't have CCRAM, so we use the 32K SRAM2 for this. -#define CACHE_MEM_START_ADDR (0x10000000) // SRAM2 data RAM, 32k -#define FLASH_SECTOR_SIZE_MAX (0x00800) // 2k max +#define CACHE_MEM_START_ADDR (&_ram_fs_cache_start) // End of SRAM2 RAM segment-2k +#define FLASH_SECTOR_SIZE_MAX (_ram_fs_cache_block_size) // 2k max #define FLASH_MEM_SEG1_START_ADDR ((long)&_flash_fs_start) #define FLASH_MEM_SEG1_NUM_BLOCKS ((&_flash_fs_end - &_flash_fs_start) / 512) diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c index c55fe76173..b7636ce270 100644 --- a/ports/stm32/mphalport.c +++ b/ports/stm32/mphalport.c @@ -100,7 +100,7 @@ void mp_hal_ticks_cpu_enable(void) { } void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) { - #if defined(STM32L476xx) || defined(STM32L486xx) + #if defined(STM32L476xx) || defined(STM32L496xx) if (gpio == GPIOG) { // Port G pins 2 thru 15 are powered using VddIO2 on these MCUs. HAL_PWREx_EnableVddIO2(); diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c index b03a3a357b..0cf0753bdf 100644 --- a/ports/stm32/system_stm32.c +++ b/ports/stm32/system_stm32.c @@ -215,7 +215,7 @@ void SystemInit(void) #endif /* Reset the RCC clock configuration to the default reset state ------------*/ - /* Set HSION bit */ + /* Set configured startup clk source */ RCC->CR |= CONFIG_RCC_CR_1ST; /* Reset CFGR register */ @@ -411,7 +411,7 @@ void SystemClock_Config(void) #endif RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; #elif defined(STM32L4) - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI; + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI; RCC_OscInitStruct.LSEState = RCC_LSE_ON; RCC_OscInitStruct.MSIState = RCC_MSI_ON; RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT; @@ -571,7 +571,7 @@ void SystemClock_Config(void) |RCC_PERIPHCLK_RNG |RCC_PERIPHCLK_RTC; PeriphClkInitStruct.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1; /* PLLSAI is used to clock USB, ADC, I2C1 and RNG. The frequency is - HSE(8MHz)/PLLM(2)*PLLSAI1N(24)/PLLSAIQ(2) = 48MHz. See the STM32CubeMx + MSI(4MHz)/PLLM(1)*PLLSAI1N(24)/PLLSAIQ(2) = 48MHz. See the STM32CubeMx application or the reference manual. */ PeriphClkInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI1; PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1; From 4005c635716b2039e933c073507844e443fb5c2a Mon Sep 17 00:00:00 2001 From: Tobias Badertscher Date: Fri, 18 May 2018 09:04:53 +0200 Subject: [PATCH 672/828] stm32/boards: Add board ld and af.csv files for STM32L496 MCU. --- ports/stm32/boards/stm32l496_af.csv | 142 ++++++++++++++++++++++++++++ ports/stm32/boards/stm32l496xg.ld | 35 +++++++ 2 files changed, 177 insertions(+) create mode 100644 ports/stm32/boards/stm32l496_af.csv create mode 100644 ports/stm32/boards/stm32l496xg.ld diff --git a/ports/stm32/boards/stm32l496_af.csv b/ports/stm32/boards/stm32l496_af.csv new file mode 100644 index 0000000000..874cf0de0a --- /dev/null +++ b/ports/stm32/boards/stm32l496_af.csv @@ -0,0 +1,142 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,,, +,,SYS_AF,TIM1/TIM2/TIM5/TIM8/LPTIM1,TIM1/TIM2/TIM3/TIM4/TIM5,TIM8,I2C1/I2C2/I2C3,SPI1/SPI2,SPI3/DFSDM,USART1/USART2/USART3,UART4/UART5/LPUART1,CAN1/TSC,OTG_FS/QUADSPI,LCD,SDMMC1/COMP1/COMP2/FMC/SWPMI1,SAI1/SAI2,TIM2/TIM15/TIM16/TIM17/LPTIM2,EVENTOUT,ADC,COMP,DAC +PortA,PA0,,TIM2_CH1,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,,,SAI1_EXTCLK,TIM2_ETR,EVENTOUT,ADC12_IN5,, +PortA,PA1,,TIM2_CH2,TIM5_CH2,,I2C1_SMBA,SPI1_SCK,,USART2_RTS_DE,UART4_RX,,,LCD_SEG0,,,TIM15_CH1N,EVENTOUT,ADC12_IN6,, +PortA,PA2,,TIM2_CH3,TIM5_CH3,,,,,USART2_TX,LPUART1_TX,,QUADSPI_BK1_NCS,LCD_SEG1,,SAI2_EXTCLK,TIM15_CH1,EVENTOUT,ADC12_IN7,, +PortA,PA3,,TIM2_CH4,TIM5_CH4,,,,,USART2_RX,LPUART1_RX,,QUADSPI_CLK,LCD_SEG2,,SAI1_MCLK_A,TIM15_CH2,EVENTOUT,ADC12_IN8,, +PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS,USART2_CK,,,DCMI_HSYNC,,,SAI1_FS_B,LPTIM2_OUT,EVENTOUT,ADC12_IN9,,DAC1_OUT1 +PortA,PA5,,TIM2_CH1,TIM2_ETR,TIM8_CH1N,,SPI1_SCK,,,,,,,,,LPTIM2_ETR,EVENTOUT,ADC12_IN10,,DAC1_OUT2 +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,DCMI_PIXCLK,SPI1_MISO,,USART3_CTS,LPUART1_CTS,,QUADSPI_BK1_IO3,LCD_SEG3,TIM1_BKIN_COMP2,TIM8_BKIN_COMP2,TIM16_CH1,EVENTOUT,ADC12_IN11,, +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,I2C3_SCL,SPI1_MOSI,,,,,QUADSPI_BK1_IO2,LCD_SEG4,,,TIM17_CH1,EVENTOUT,ADC12_IN12,, +PortA,PA8,MCO,TIM1_CH1,,,,,,USART1_CK,,,OTG_FS_SOF,LCD_COM0,SWPMI1_IO,SAI1_SCK_A,LPTIM2_OUT,EVENTOUT,,, +PortA,PA9,,TIM1_CH2,,SPI2_SCK,I2C1_SCL,DCMI_D0,,USART1_TX,,,,LCD_COM1,,SAI1_FS_A,TIM15_BKIN,EVENTOUT,,, +PortA,PA10,,TIM1_CH3,,,I2C1_SDA,DCMI_D1,,USART1_RX,,,OTG_FS_ID,LCD_COM2,,SAI1_SD_A,TIM17_BKIN,EVENTOUT,,, +PortA,PA11,,TIM1_CH4,TIM1_BKIN2,,,SPI1_MISO,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,TIM1_BKIN2_COMP1,,,EVENTOUT,,, +PortA,PA12,,TIM1_ETR,,,,SPI1_MOSI,,USART1_RTS_DE,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT,,, +PortA,PA13,JTMS/SWDIO,IR_OUT,,,,,,,,,OTG_FS_NOE,,SWPMI1_TX,SAI1_SD_B,,EVENTOUT,,, +PortA,PA14,JTCK/SWCLK,LPTIM1_OUT,,,I2C1_SMBA,I2C4_SMBA,,,,,OTG_FS_SOF,,SWPMI1_RX,SAI1_FS_B,,EVENTOUT,,, +PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,USART2_RX,,SPI1_NSS,SPI3_NSS,USART3_RTS_DE,UART4_RTS_DE,TSC_G3_IO1,,LCD_SEG17,SWPMI1_SUSPEND,SAI2_FS_B,,EVENTOUT,,, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,SPI1_NSS,,USART3_CK,,,QUADSPI_BK1_IO1,LCD_SEG5,COMP1_OUT,SAI1_EXTCLK,,EVENTOUT,ADC12_IN15,, +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM1_DATIN0,USART3_RTS_DE,LPUART1_RTS_DE,,QUADSPI_BK1_IO0,LCD_SEG6,,,LPTIM2_IN1,EVENTOUT,ADC12_IN16,COMP1_INM, +PortB,PB2,RTC_OUT,LPTIM1_OUT,,,I2C3_SMBA,,DFSDM1_CKIN0,,,,,LCD_VLCD,,,,EVENTOUT,,COMP1_INP, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK,USART1_RTS_DE,,,OTG_FS_CRS_SYNC,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT,,COMP2_INM, +PortB,PB4,NJTRST,,TIM3_CH1,,I2C3_SDA,SPI1_MISO,SPI3_MISO,USART1_CTS,UART5_RTS_DE,TSC_G2_IO1,DCMI_D12,LCD_SEG8,,SAI1_MCLK_B,TIM17_BKIN,EVENTOUT,,COMP2_INP, +PortB,PB5,,LPTIM1_IN1,TIM3_CH2,CAN2_RX,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI,USART1_CK,UART5_CTS,TSC_G2_IO2,DCMI_D10,LCD_SEG9,COMP2_OUT,SAI1_SD_B,TIM16_BKIN,EVENTOUT,,, +PortB,PB6,,LPTIM1_ETR,TIM4_CH1,TIM8_BKIN2,I2C1_SCL,I2C4_SCL,DFSDM1_DATIN5,USART1_TX,CAN2_TX,TSC_G2_IO3,DCMI_D5,,TIM8_BKIN2_COMP2,SAI1_FS_B,TIM16_CH1N,EVENTOUT,,COMP2_INP, +PortB,PB7,,LPTIM1_IN2,TIM4_CH2,TIM8_BKIN,I2C1_SDA,I2C4_SDA,DFSDM1_CKIN5,USART1_RX,UART4_CTS,TSC_G2_IO4,DCMI_VSYNC,LCD_SEG21,FMC_NL,TIM8_BKIN_COMP1,TIM17_CH1N,EVENTOUT,,COMP2_INM, +PortB,PB8,,,TIM4_CH3,,I2C1_SCL,,DFSDM1_DATIN6,,,CAN1_RX,DCMI_D6,LCD_SEG16,SDMMC1_D4,SAI1_MCLK_A,TIM16_CH1,EVENTOUT,,, +PortB,PB9,,IR_OUT,TIM4_CH4,,I2C1_SDA,SPI2_NSS,DFSDM1_CKIN6,,,CAN1_TX,DCMI_D7,LCD_COM3,SDMMC1_D5,SAI1_FS_A,TIM17_CH1,EVENTOUT,,, +PortB,PB10,,TIM2_CH3,,I2C4_SCL,I2C2_SCL,SPI2_SCK,DFSDM1_DATIN7,USART3_TX,LPUART1_RX,TSC_SYNC,QUADSPI_CLK,LCD_SEG10,COMP1_OUT,SAI1_SCK_A,,EVENTOUT,,, +PortB,PB11,,TIM2_CH4,,I2C4_SDA,I2C2_SDA,,DFSDM1_CKIN7,USART3_RX,LPUART1_TX,,QUADSPI_BK1_NCS,LCD_SEG11,COMP2_OUT,,,EVENTOUT,,, +PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM1_DATIN1,USART3_CK,LPUART1_RTS_DE,TSC_G1_IO1,CAN2_RX,LCD_SEG12,SWPMI1_IO,SAI2_FS_A,TIM15_BKIN,EVENTOUT,,, +PortB,PB13,,TIM1_CH1N,,,I2C2_SCL,SPI2_SCK,DFSDM1_CKIN1,USART3_CTS,LPUART1_CTS,TSC_G1_IO2,CAN2_TX,LCD_SEG13,SWPMI1_TX,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,,, +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,I2C2_SDA,SPI2_MISO,DFSDM1_DATIN2,USART3_RTS_DE,,TSC_G1_IO3,,LCD_SEG14,SWPMI1_RX,SAI2_MCLK_A,TIM15_CH1,EVENTOUT,,, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI,DFSDM1_CKIN2,,,TSC_G1_IO4,,LCD_SEG15,SWPMI1_SUSPEND,SAI2_SD_A,TIM15_CH2,EVENTOUT,,, +PortC,PC0,,LPTIM1_IN1,I2C4_SCL,,I2C3_SCL,,DFSDM1_DATIN4,,LPUART1_RX,,,LCD_SEG18,,,LPTIM2_IN1,EVENTOUT,ADC123_IN1,, +PortC,PC1,TRACED0,LPTIM1_OUT,I2C4_SDA,SPI2_MOSI,I2C3_SDA,,DFSDM1_CKIN4,,LPUART1_TX,,QUADSPI_BK2_IO0,LCD_SEG19,,SAI1_SD_A,,EVENTOUT,ADC123_IN2,, +PortC,PC2,,LPTIM1_IN2,,,,SPI2_MISO,DFSDM1_CKOUT,,,,QUADSPI_BK2_IO1,LCD_SEG20,,,,EVENTOUT,ADC123_IN3,, +PortC,PC3,,LPTIM1_ETR,,,,SPI2_MOSI,,,,,QUADSPI_BK2_IO2,LCD_VLCD,,SAI1_SD_A,LPTIM2_ETR,EVENTOUT,ADC123_IN4,, +PortC,PC4,,,,,,,,USART3_TX,,,QUADSPI_BK2_IO3,LCD_SEG22,,,,EVENTOUT,ADC12_IN13,COMP1_INM, +PortC,PC5,,,,,,,,USART3_RX,,,,LCD_SEG23,,,,EVENTOUT,ADC12_IN14,COMP1_INP, +PortC,PC6,,,TIM3_CH1,TIM8_CH1,,,DFSDM1_CKIN3,,,TSC_G4_IO1,DCMI_D0,LCD_SEG24,SDMMC1_D6,SAI2_MCLK_A,,EVENTOUT,,, +PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,DFSDM1_DATIN3,,,TSC_G4_IO2,DCMI_D1,LCD_SEG25,SDMMC1_D7,SAI2_MCLK_B,,EVENTOUT,,, +PortC,PC8,,,TIM3_CH3,TIM8_CH3,,,,,,TSC_G4_IO3,DCMI_D2,LCD_SEG26,SDMMC1_D0,,,EVENTOUT,,, +PortC,PC9,,TIM8_BKIN2,TIM3_CH4,TIM8_CH4,DCMI_D3,,I2C3_SDA,,,TSC_G4_IO4,OTG_FS_NOE,LCD_SEG27,SDMMC1_D1,SAI2_EXTCLK,TIM8_BKIN2_COMP1,EVENTOUT,,, +PortC,PC10,TRACED1,,,,,,SPI3_SCK,USART3_TX,UART4_TX,TSC_G3_IO2,DCMI_D8,LCD_COM4/LCD_SEG28/LCD_SEG40,SDMMC1_D2,SAI2_SCK_B,,EVENTOUT,,, +PortC,PC11,,,,,,QUADSPI_BK2_NCS,SPI3_MISO,USART3_RX,UART4_RX,TSC_G3_IO3,DCMI_D4,LCD_COM5/LCD_SEG29/LCD_SEG41,SDMMC1_D3,SAI2_MCLK_B,,EVENTOUT,,, +PortC,PC12,TRACED3,,,,,,SPI3_MOSI,USART3_CK,UART5_TX,TSC_G3_IO4,DCMI_D9,LCD_COM6/LCD_SEG30/LCD_SEG42,SDMMC1_CK,SAI2_SD_B,,EVENTOUT,,, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT,,, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,,, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,,, +PortD,PD0,,,,,,SPI2_NSS,DFSDM1_DATIN7,,,CAN1_RX,,,FMC_D2,,,EVENTOUT,,, +PortD,PD1,,,,,,SPI2_SCK,DFSDM1_CKIN7,,,CAN1_TX,,,FMC_D3,,,EVENTOUT,,, +PortD,PD2,TRACED2,,TIM3_ETR,,,,,USART3_RTS_DE,UART5_RX,TSC_SYNC,DCMI_D11,LCD_COM7/LCD_SEG31/LCD_SEG43,SDMMC1_CMD,,,EVENTOUT,,, +PortD,PD3,,,,SPI2_SCK,DCMI_D5,SPI2_MISO,DFSDM1_DATIN0,USART2_CTS,,,QUADSPI_BK2_NCS,,FMC_CLK,,,EVENTOUT,,, +PortD,PD4,,,,,,SPI2_MOSI,DFSDM1_CKIN0,USART2_RTS_DE,,,QUADSPI_BK2_IO0,,FMC_NOE,,,EVENTOUT,,, +PortD,PD5,,,,,,,,USART2_TX,,,QUADSPI_BK2_IO1,,FMC_NWE,,,EVENTOUT,,, +PortD,PD6,,,,,DCMI_D10,QUADSPI_BK2_IO1,DFSDM1_DATIN1,USART2_RX,,,QUADSPI_BK2_IO2,,FMC_NWAIT,SAI1_SD_A,,EVENTOUT,,, +PortD,PD7,,,,,,,DFSDM1_CKIN1,USART2_CK,,,QUADSPI_BK2_IO3,,FMC_NE1,,,EVENTOUT,,, +PortD,PD8,,,,,,,,USART3_TX,,,DCMI_HSYNC,LCD_SEG28,FMC_D13,,,EVENTOUT,,, +PortD,PD9,,,,,,,,USART3_RX,,,DCMI_PIXCLK,LCD_SEG29,FMC_D14,SAI2_MCLK_A,,EVENTOUT,,, +PortD,PD10,,,,,,,,USART3_CK,,TSC_G6_IO1,,LCD_SEG30,FMC_D15,SAI2_SCK_A,,EVENTOUT,,, +PortD,PD11,,,,,I2C4_SMBA,,,USART3_CTS,,TSC_G6_IO2,,LCD_SEG31,FMC_A16,SAI2_SD_A,LPTIM2_ETR,EVENTOUT,,, +PortD,PD12,,,TIM4_CH1,,I2C4_SCL,,,USART3_RTS_DE,,TSC_G6_IO3,,LCD_SEG32,FMC_A17,SAI2_FS_A,LPTIM2_IN1,EVENTOUT,,, +PortD,PD13,,,TIM4_CH2,,I2C4_SDA,,,,,TSC_G6_IO4,,LCD_SEG33,FMC_A18,,LPTIM2_OUT,EVENTOUT,,, +PortD,PD14,,,TIM4_CH3,,,,,,,,,LCD_SEG34,FMC_D0,,,EVENTOUT,,, +PortD,PD15,,,TIM4_CH4,,,,,,,,,LCD_SEG35,FMC_D1,,,EVENTOUT,,, +PortE,PE0,,,TIM4_ETR,,,,,,,,DCMI_D2,LCD_SEG36,FMC_NBL0,,TIM16_CH1,EVENTOUT,,, +PortE,PE1,,,,,,,,,,,DCMI_D3,LCD_SEG37,FMC_NBL1,,TIM17_CH1,EVENTOUT,,, +PortE,PE2,TRACECK,,TIM3_ETR,,,,,,,TSC_G7_IO1,,LCD_SEG38,FMC_A23,SAI1_MCLK_A,,EVENTOUT,,, +PortE,PE3,TRACED0,,TIM3_CH1,,,,,,,TSC_G7_IO2,,LCD_SEG39,FMC_A19,SAI1_SD_B,,EVENTOUT,,, +PortE,PE4,TRACED1,,TIM3_CH2,,,,DFSDM1_DATIN3,,,TSC_G7_IO3,DCMI_D4,,FMC_A20,SAI1_FS_A,,EVENTOUT,,, +PortE,PE5,TRACED2,,TIM3_CH3,,,,DFSDM1_CKIN3,,,TSC_G7_IO4,DCMI_D6,,FMC_A21,SAI1_SCK_A,,EVENTOUT,,, +PortE,PE6,TRACED3,,TIM3_CH4,,,,,,,,DCMI_D7,,FMC_A22,SAI1_SD_A,,EVENTOUT,,, +PortE,PE7,,TIM1_ETR,,,,,DFSDM1_DATIN2,,,,,,FMC_D4,SAI1_SD_B,,EVENTOUT,,, +PortE,PE8,,TIM1_CH1N,,,,,DFSDM1_CKIN2,,,,,,FMC_D5,SAI1_SCK_B,,EVENTOUT,,, +PortE,PE9,,TIM1_CH1,,,,,DFSDM1_CKOUT,,,,,,FMC_D6,SAI1_FS_B,,EVENTOUT,,, +PortE,PE10,,TIM1_CH2N,,,,,DFSDM1_DATIN4,,,TSC_G5_IO1,QUADSPI_CLK,,FMC_D7,SAI1_MCLK_B,,EVENTOUT,,, +PortE,PE11,,TIM1_CH2,,,,,DFSDM1_CKIN4,,,TSC_G5_IO2,QUADSPI_BK1_NCS,,FMC_D8,,,EVENTOUT,,, +PortE,PE12,,TIM1_CH3N,,,,SPI1_NSS,DFSDM1_DATIN5,,,TSC_G5_IO3,QUADSPI_BK1_IO0,,FMC_D9,,,EVENTOUT,,, +PortE,PE13,,TIM1_CH3,,,,SPI1_SCK,DFSDM1_CKIN5,,,TSC_G5_IO4,QUADSPI_BK1_IO1,,FMC_D10,,,EVENTOUT,,, +PortE,PE14,,TIM1_CH4,TIM1_BKIN2,TIM1_BKIN2_COMP2,,SPI1_MISO,,,,,QUADSPI_BK1_IO2,,FMC_D11,,,EVENTOUT,,, +PortE,PE15,,TIM1_BKIN,,TIM1_BKIN_COMP1,,SPI1_MOSI,,,,,QUADSPI_BK1_IO3,,FMC_D12,,,EVENTOUT,,, +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT,,, +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT,,, +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT,,, +PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN6,, +PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN7,, +PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN8,, +PortF,PF6,,TIM5_ETR,TIM5_CH1,,,,,,,,QUADSPI_BK1_IO3,,,SAI1_SD_B,,EVENTOUT,ADC3_IN9,, +PortF,PF7,,,TIM5_CH2,,,,,,,,QUADSPI_BK1_IO2,,,SAI1_MCLK_B,,EVENTOUT,ADC3_IN10,, +PortF,PF8,,,TIM5_CH3,,,,,,,,QUADSPI_BK1_IO0,,,SAI1_SCK_B,,EVENTOUT,ADC3_IN11,, +PortF,PF9,,,TIM5_CH4,,,,,,,,QUADSPI_BK1_IO1,,,SAI1_FS_B,TIM15_CH1,EVENTOUT,ADC3_IN12,, +PortF,PF10,,,,QUADSPI_CLK,,,,,,,DCMI_D11,,,,TIM15_CH2,EVENTOUT,ADC3_IN13,, +PortF,PF11,,,,,,,,,,,DCMI_D12,,,,,EVENTOUT,,, +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT,,, +PortF,PF13,,,,,I2C4_SMBA,,DFSDM1_DATIN6,,,,,,FMC_A7,,,EVENTOUT,,, +PortF,PF14,,,,,I2C4_SCL,,DFSDM1_CKIN6,,,TSC_G8_IO1,,,FMC_A8,,,EVENTOUT,,, +PortF,PF15,,,,,I2C4_SDA,,,,,TSC_G8_IO2,,,FMC_A9,,,EVENTOUT,,, +PortG,PG0,,,,,,,,,,TSC_G8_IO3,,,FMC_A10,,,EVENTOUT,,, +PortG,PG1,,,,,,,,,,TSC_G8_IO4,,,FMC_A11,,,EVENTOUT,,, +PortG,PG2,,,,,,SPI1_SCK,,,,,,,FMC_A12,SAI2_SCK_B,,EVENTOUT,,, +PortG,PG3,,,,,,SPI1_MISO,,,,,,,FMC_A13,SAI2_FS_B,,EVENTOUT,,, +PortG,PG4,,,,,,SPI1_MOSI,,,,,,,FMC_A14,SAI2_MCLK_B,,EVENTOUT,,, +PortG,PG5,,,,,,SPI1_NSS,,,LPUART1_CTS,,,,FMC_A15,SAI2_SD_B,,EVENTOUT,,, +PortG,PG6,,,,,I2C3_SMBA,,,,LPUART1_RTS_DE,,,,,,,EVENTOUT,,, +PortG,PG7,,,,,I2C3_SCL,,,,LPUART1_TX,,,,FMC_INT,SAI1_MCLK_A,,EVENTOUT,,, +PortG,PG8,,,,,I2C3_SDA,,,,LPUART1_RX,,,,,,,EVENTOUT,,, +PortG,PG9,,,,,,,SPI3_SCK,USART1_TX,,,,,FMC_NCE/FMC_NE2,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,,, +PortG,PG10,,LPTIM1_IN1,,,,,SPI3_MISO,USART1_RX,,,,,FMC_NE3,SAI2_FS_A,TIM15_CH1,EVENTOUT,,, +PortG,PG11,,LPTIM1_IN2,,,,,SPI3_MOSI,USART1_CTS,,,,,,SAI2_MCLK_A,TIM15_CH2,EVENTOUT,,, +PortG,PG12,,LPTIM1_ETR,,,,,SPI3_NSS,USART1_RTS_DE,,,,,FMC_NE4,SAI2_SD_A,,EVENTOUT,,, +PortG,PG13,,,,,I2C1_SDA,,,USART1_CK,,,,,FMC_A24,,,EVENTOUT,,, +PortG,PG14,,,,,I2C1_SCL,,,,,,,,FMC_A25,,,EVENTOUT,,, +PortG,PG15,,LPTIM1_OUT,,,I2C1_SMBA,,,,,,DCMI_D13,,,,,EVENTOUT,,, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT,,, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT,,, +PortH,PH2,,,,QUADSPI_BK2_IO0,,,,,,,,,,,,EVENTOUT,,, +PortH,PH3,,,,,,,,,,,,,,,,EVENTOUT,,, +PortH,PH4,,,,,I2C2_SCL,,,,,,,,,,,EVENTOUT,,, +PortH,PH5,,,,,I2C2_SDA,,,,,,DCMI_PIXCLK,,,,,EVENTOUT,,, +PortH,PH6,,,,,I2C2_SMBA,,,,,,DCMI_D8,,,,,EVENTOUT,,, +PortH,PH7,,,,,I2C3_SCL,,,,,,DCMI_D9,,,,,EVENTOUT,,, +PortH,PH8,,,,,I2C3_SDA,,,,,,DCMI_HSYNC,,,,,EVENTOUT,,, +PortH,PH9,,,,,I2C3_SMBA,,,,,,DCMI_D0,,,,,EVENTOUT,,, +PortH,PH10,,,TIM5_CH1,,,,,,,,DCMI_D1,,,,,EVENTOUT,,, +PortH,PH11,,,TIM5_CH2,,,,,,,,DCMI_D2,,,,,EVENTOUT,,, +PortH,PH12,,,TIM5_CH3,,,,,,,,DCMI_D3,,,,,EVENTOUT,,, +PortH,PH13,,,,TIM8_CH1N,,,,,,CAN1_TX,,,,,,EVENTOUT,,, +PortH,PH14,,,,TIM8_CH2N,,,,,,,DCMI_D4,,,,,EVENTOUT,,, +PortH,PH15,,,,TIM8_CH3N,,,,,,,DCMI_D11,,,,,EVENTOUT,,, +PortI,PI0,,,TIM5_CH4,,,SPI2_NSS,,,,,DCMI_D13,,,,,EVENTOUT,,, +PortI,PI1,,,,,,SPI2_SCK,,,,,DCMI_D8,,,,,EVENTOUT,,, +PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,,,,,DCMI_D9,,,,,EVENTOUT,,, +PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI,,,,,DCMI_D10,,,,,EVENTOUT,,, +PortI,PI4,,,,TIM8_BKIN,,,,,,,DCMI_D5,,,,,EVENTOUT,,, +PortI,PI5,,,,TIM8_CH1,,,,,,,DCMI_VSYNC,,,,,EVENTOUT,,, +PortI,PI6,,,,TIM8_CH2,,,,,,,DCMI_D6,,,,,EVENTOUT,,, +PortI,PI7,,,,TIM8_CH3,,,,,,,DCMI_D7,,,,,EVENTOUT,,, +PortI,PI8,,,,,,,,,,,DCMI_D12,,,,,EVENTOUT,,, +PortI,PI9,,,,,,,,,,CAN1_RX,,,,,,EVENTOUT,,, +PortI,PI10,,,,,,,,,,,,,,,,EVENTOUT,,, +PortI,PI11,,,,,,,,,,,,,,,,EVENTOUT,,, diff --git a/ports/stm32/boards/stm32l496xg.ld b/ports/stm32/boards/stm32l496xg.ld new file mode 100644 index 0000000000..88221170b4 --- /dev/null +++ b/ports/stm32/boards/stm32l496xg.ld @@ -0,0 +1,35 @@ +/* + GNU linker script for STM32L496XG +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sectors 0-7 */ + FLASH_TEXT (rx) : ORIGIN = 0x08004000, LENGTH = 596K /* sectors 8-305 */ + FLASH_FS (r) : ORIGIN = 0x08099000, LENGTH = 412K /* sectors 306-511 412 KiB */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 256K + SRAM2 (xrw) : ORIGIN = 0x20040000, LENGTH = 62K /* leave 2K for flash fs cache */ + FS_CACHE(xrw) : ORIGIN = 0x2004f800, LENGTH = 2K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define the top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM) + LENGTH(SRAM2); + +/* RAM extents for the garbage collector */ +_ram_fs_cache_start = ORIGIN(FS_CACHE); +_ram_fs_cache_block_size = LENGTH(FS_CACHE); +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM) + LENGTH(SRAM2); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x2001C000; /* tunable */ + +_flash_fs_start = ORIGIN(FLASH_FS); +_flash_fs_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); From 769e37b64619cf1dcf8a865d39b1341afaddbd2a Mon Sep 17 00:00:00 2001 From: Tobias Badertscher Date: Fri, 18 May 2018 09:05:32 +0200 Subject: [PATCH 673/828] stm32/boards: Add config files for new board, STM32L496GDISC. --- .../boards/STM32L496GDISC/mpconfigboard.h | 52 +++ .../boards/STM32L496GDISC/mpconfigboard.mk | 7 + ports/stm32/boards/STM32L496GDISC/pins.csv | 140 ++++++ .../STM32L496GDISC/stm32l4xx_hal_conf.h | 421 ++++++++++++++++++ 4 files changed, 620 insertions(+) create mode 100644 ports/stm32/boards/STM32L496GDISC/mpconfigboard.h create mode 100644 ports/stm32/boards/STM32L496GDISC/mpconfigboard.mk create mode 100644 ports/stm32/boards/STM32L496GDISC/pins.csv create mode 100644 ports/stm32/boards/STM32L496GDISC/stm32l4xx_hal_conf.h diff --git a/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h b/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h new file mode 100644 index 0000000000..6a17d74d3a --- /dev/null +++ b/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h @@ -0,0 +1,52 @@ +#define MICROPY_HW_BOARD_NAME "L496G-DISCO" +#define MICROPY_HW_MCU_NAME "STM32L496" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_TIMER (1) +#define MICROPY_HW_ENABLE_USB (1) + +// MSI is used and is 4MHz, +// Resulting core frequency is 80MHz: +#define MICROPY_HW_CLK_PLLM (1) +#define MICROPY_HW_CLK_PLLN (40) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV7) +#define MICROPY_HW_CLK_PLLR (RCC_PLLR_DIV2) +#define MICROPY_HW_CLK_PLLQ (RCC_PLLQ_DIV2) + +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 + +// USART config +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_D6) +// USART 2 is connected to the virtual com port on the ST-LINK +#define MICROPY_HW_UART_REPL PYB_UART_2 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_G14) +#define MICROPY_HW_I2C1_SDA (pin_G13) +#define MICROPY_HW_I2C2_SCL (pin_H4) +#define MICROPY_HW_I2C2_SDA (pin_B14) + +// SPI busses +// -> To the arduino connector +#define MICROPY_HW_SPI1_NSS (pin_A15) +#define MICROPY_HW_SPI1_SCK (pin_A5) +#define MICROPY_HW_SPI1_MISO (pin_B4) +#define MICROPY_HW_SPI1_MOSI (pin_B5) + +// Use Sel from joystick. Joystick is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_C13) +#define MICROPY_HW_USRSW_PULL (GPIO_PULLDOWN) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LED (The orange LED is controlled over MFX) +#define MICROPY_HW_LED1 (pin_B13) // Green +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) +// USB config +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/STM32L496GDISC/mpconfigboard.mk b/ports/stm32/boards/STM32L496GDISC/mpconfigboard.mk new file mode 100644 index 0000000000..3a61746556 --- /dev/null +++ b/ports/stm32/boards/STM32L496GDISC/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = l4 +CMSIS_MCU = STM32L496xx +AF_FILE = boards/stm32l496_af.csv +LD_FILES = boards/stm32l496xg.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08004000 +OPENOCD_CONFIG = boards/openocd_stm32l4.cfg diff --git a/ports/stm32/boards/STM32L496GDISC/pins.csv b/ports/stm32/boards/STM32L496GDISC/pins.csv new file mode 100644 index 0000000000..2ee054032b --- /dev/null +++ b/ports/stm32/boards/STM32L496GDISC/pins.csv @@ -0,0 +1,140 @@ +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA11,PA11 +PA12,PA12 +PA13,PA13 +PA14,PA14 +PA15,PA15 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PB3,PB3 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PB10,PB10 +PB11,PB11 +PB12,PB12 +PB13,PB13 +PB14,PB14 +PB15,PB15 +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PC4,PC4 +PC5,PC5 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PC13,PC13 +PC14,PC14 +PC15,PC15 +PD0,PD0 +PD1,PD1 +PD2,PD2 +PD3,PD3 +PD4,PD4 +PD5,PD5 +PD6,PD6 +PD7,PD7 +PD8,PD8 +PD9,PD9 +PD10,PD10 +PD11,PD11 +PD12,PD12 +PD13,PD13 +PD14,PD14 +PD15,PD15 +PE0,PE0 +PE1,PE1 +PE2,PE2 +PE3,PE3 +PE4,PE4 +PE5,PE5 +PE6,PE6 +PE7,PE7 +PE8,PE8 +PE9,PE9 +PE10,PE10 +PE11,PE11 +PE12,PE12 +PE13,PE13 +PE14,PE14 +PE15,PE15 +PF0,PF0 +PF1,PF1 +PF2,PF2 +PF3,PF3 +PF4,PF4 +PF5,PF5 +PF6,PF6 +PF7,PF7 +PF8,PF8 +PF9,PF9 +PF10,PF10 +PF11,PF11 +PF12,PF12 +PF13,PF13 +PF14,PF14 +PF15,PF15 +PG0,PG0 +PG1,PG1 +PG2,PG2 +PG3,PG3 +PG4,PG4 +PG5,PG5 +PG6,PG6 +PG7,PG7 +PG8,PG8 +PG9,PG9 +PG10,PG10 +PG11,PG11 +PG12,PG12 +PG13,PG13 +PG14,PG14 +PG15,PG15 +PH0,PH0 +PH1,PH1 +PH2,PH2 +PH3,PH3 +PH4,PH4 +PH5,PH5 +PH6,PH6 +PH7,PH7 +PH8,PH8 +PH9,PH9 +PH10,PH10 +PH11,PH11 +PH12,PH12 +PH13,PH13 +PH14,PH14 +PH15,PH15 +PI0,PI0 +PI1,PI1 +PI2,PI2 +PI3,PI3 +PI4,PI4 +PI5,PI5 +PI6,PI6 +PI7,PI7 +PI8,PI8 +PI9,PI9 +PI10,PI10 +PI11,PI11 diff --git a/ports/stm32/boards/STM32L496GDISC/stm32l4xx_hal_conf.h b/ports/stm32/boards/STM32L496GDISC/stm32l4xx_hal_conf.h new file mode 100644 index 0000000000..884db5ef1a --- /dev/null +++ b/ports/stm32/boards/STM32L496GDISC/stm32l4xx_hal_conf.h @@ -0,0 +1,421 @@ +/** + ****************************************************************************** + * @file stm32l4xx_hal_conf.h + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2018 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32L4xx_HAL_CONF_H +#define __STM32L4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ + +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +/*#define HAL_CRYP_MODULE_ENABLED */ +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_COMP_MODULE_ENABLED */ +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +/*#define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_DFSDM_MODULE_ENABLED */ +/*#define HAL_DSI_MODULE_ENABLED */ +/*#define HAL_FIREWALL_MODULE_ENABLED */ +/*#define HAL_GFXMMU_MODULE_ENABLED */ +/*#define HAL_HCD_MODULE_ENABLED */ +/*#define HAL_HASH_MODULE_ENABLED */ +/*#define HAL_I2S_MODULE_ENABLED */ +/*#define HAL_IRDA_MODULE_ENABLED */ +/*#define HAL_IWDG_MODULE_ENABLED */ +/*#define HAL_LTDC_MODULE_ENABLED */ +/*#define HAL_LCD_MODULE_ENABLED */ +/*#define HAL_LPTIM_MODULE_ENABLED */ +/*#define HAL_NAND_MODULE_ENABLED */ +/*#define HAL_NOR_MODULE_ENABLED */ +/*#define HAL_OPAMP_MODULE_ENABLED */ +/*#define HAL_OSPI_MODULE_ENABLED */ +#define HAL_PCD_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +/* #define HAL_SMBUS_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +#define HAL_SPI_MODULE_ENABLED +/*#define HAL_SRAM_MODULE_ENABLED */ +/*#define HAL_SWPMI_MODULE_ENABLED */ +#define HAL_TIM_MODULE_ENABLED +/*#define HAL_TSC_MODULE_ENABLED */ +#define HAL_UART_MODULE_ENABLED +/*#define HAL_USART_MODULE_ENABLED */ +/*#define HAL_WWDG_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED + +/* ########################## Oscillator Values adaptation ####################*/ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal Multiple Speed oscillator (MSI) default value. + * This value is the default MSI range value after Reset. + */ +#if !defined (MSI_VALUE) + #define MSI_VALUE ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* MSI_VALUE */ +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + + /** + * @brief Internal High Speed oscillator (HSI48) value for USB FS, SDMMC and RNG. + * This internal oscillator is mainly dedicated to provide a high precision clock to + * the USB peripheral by means of a special Clock Recovery System (CRS) circuitry. + * When the CRS is not used, the HSI48 RC oscillator runs on it default frequency + * which is subject to manufacturing process variations. + */ + #if !defined (HSI48_VALUE) + #define HSI48_VALUE ((uint32_t)48000000U) /*!< Value of the Internal High Speed oscillator for USB FS/SDMMC/RNG in Hz. + The real value my vary depending on manufacturing process variations.*/ + #endif /* HSI48_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)32000) /*!< LSI Typical Value in Hz*/ +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + * This value is used by the UART, RTC HAL module to compute the system frequency + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External oscillator in Hz*/ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for LSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for SAI1 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source + * frequency. + */ +#if !defined (EXTERNAL_SAI1_CLOCK_VALUE) + #define EXTERNAL_SAI1_CLOCK_VALUE ((uint32_t)48000) /*!< Value of the SAI1 External clock source in Hz*/ +#endif /* EXTERNAL_SAI1_CLOCK_VALUE */ + +/** + * @brief External clock source for SAI2 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source + * frequency. + */ +#if !defined (EXTERNAL_SAI2_CLOCK_VALUE) + #define EXTERNAL_SAI2_CLOCK_VALUE ((uint32_t)48000) /*!< Value of the SAI2 External clock source in Hz*/ +#endif /* EXTERNAL_SAI2_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver + * Activated: CRC code is present inside driver + * Deactivated: CRC code cleaned from driver + */ + +#define USE_SPI_CRC 0 + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32l4xx_hal_rcc.h" + #include "stm32l4xx_hal_rcc_ex.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32l4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32l4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_DFSDM_MODULE_ENABLED + #include "stm32l4xx_hal_dfsdm.h" +#endif /* HAL_DFSDM_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32l4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32l4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32l4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED + #include "stm32l4xx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32l4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32l4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32l4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32l4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32l4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DSI_MODULE_ENABLED + #include "stm32l4xx_hal_dsi.h" +#endif /* HAL_DSI_MODULE_ENABLED */ + +#ifdef HAL_FIREWALL_MODULE_ENABLED + #include "stm32l4xx_hal_firewall.h" +#endif /* HAL_FIREWALL_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32l4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32l4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32l4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32l4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32l4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32l4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32l4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LCD_MODULE_ENABLED + #include "stm32l4xx_hal_lcd.h" +#endif /* HAL_LCD_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED + #include "stm32l4xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32l4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_OPAMP_MODULE_ENABLED + #include "stm32l4xx_hal_opamp.h" +#endif /* HAL_OPAMP_MODULE_ENABLED */ + +#ifdef HAL_OSPI_MODULE_ENABLED + #include "stm32l4xx_hal_ospi.h" +#endif /* HAL_OSPI_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32l4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32l4xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32l4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32l4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32l4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32l4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED + #include "stm32l4xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32l4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_SWPMI_MODULE_ENABLED + #include "stm32l4xx_hal_swpmi.h" +#endif /* HAL_SWPMI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32l4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_TSC_MODULE_ENABLED + #include "stm32l4xx_hal_tsc.h" +#endif /* HAL_TSC_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32l4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32l4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32l4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32l4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32l4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32l4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32l4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +#ifdef HAL_GFXMMU_MODULE_ENABLED + #include "stm32l4xx_hal_gfxmmu.h" +#endif /* HAL_GFXMMU_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0U) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32L4xx_HAL_CONF_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ From 43d08d6dd6fab6c88eeb20663ab97d622c2ea915 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 18 May 2018 13:10:31 +1000 Subject: [PATCH 674/828] py/misc.h: Add MP_STATIC_ASSERT macro to do static assertions. --- py/misc.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/py/misc.h b/py/misc.h index 72560da1eb..e6d25b8509 100644 --- a/py/misc.h +++ b/py/misc.h @@ -50,6 +50,9 @@ typedef unsigned int uint; #define _MP_STRINGIFY(x) #x #define MP_STRINGIFY(x) _MP_STRINGIFY(x) +// Static assertion macro +#define MP_STATIC_ASSERT(cond) ((void)sizeof(char[1 - 2 * !(cond)])) + /** memory allocation ******************************************/ // TODO make a lazy m_renew that can increase by a smaller amount than requested (but by at least 1 more element) From 828ce16dc8063f11a2743cfd8fc698e0afa23cac Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 18 May 2018 13:11:02 +1000 Subject: [PATCH 675/828] py/compile: Change comment about ITER_BUF_NSLOTS to a static assertion. --- py/compile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/compile.c b/py/compile.c index 9200b346bd..c2dd914f03 100644 --- a/py/compile.c +++ b/py/compile.c @@ -3052,7 +3052,7 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) { // There are 4 slots on the stack for the iterator, and the first one is // NULL to indicate that the second one points to the iterator object. if (scope->kind == SCOPE_GEN_EXPR) { - // TODO static assert that MP_OBJ_ITER_BUF_NSLOTS == 4 + MP_STATIC_ASSERT(MP_OBJ_ITER_BUF_NSLOTS == 4); EMIT(load_null); compile_load_id(comp, qstr_arg); EMIT(load_null); From 3ea0862a6e3c97f6224548c41a225f270df4d205 Mon Sep 17 00:00:00 2001 From: Keith Wiley Date: Thu, 17 May 2018 22:30:35 -0700 Subject: [PATCH 676/828] tools/pydfu.py: Fix typo in comments. --- tools/pydfu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pydfu.py b/tools/pydfu.py index 4296f07bfb..3f11de0679 100755 --- a/tools/pydfu.py +++ b/tools/pydfu.py @@ -5,7 +5,7 @@ # details. """This module implements enough functionality to program the STM32F4xx over -DFU, without requiringdfu-util. +DFU, without requiring dfu-util. See app note AN3156 for a description of the DFU protocol. See document UM0391 for a dscription of the DFuse file. From 10500459792ce23c282515fff2c8844c66eadec0 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 14 Dec 2017 14:08:37 +0200 Subject: [PATCH 677/828] zephyr/README: Hint about existence of qemu_x86_nommu. --- ports/zephyr/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr/README.md b/ports/zephyr/README.md index 6e1ea274be..f7001af4b8 100644 --- a/ports/zephyr/README.md +++ b/ports/zephyr/README.md @@ -110,4 +110,4 @@ To make a minimal build: To run a minimal build in QEMU without requiring TAP networking setup run the following after you built image with the previous command: - ./make-minimal BOARD= run + ./make-minimal BOARD= run From 9480c188e82a73fce9a6d855fdd7269717f10b25 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 12 Jan 2018 11:19:27 +0200 Subject: [PATCH 678/828] zephyr/main: After builtin testsuite, drop to REPL. It makes sense to make even testsuite-enabled builds be suitable for interactive use. --- ports/zephyr/main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/zephyr/main.c b/ports/zephyr/main.c index 58d127ec63..a28fb37923 100644 --- a/ports/zephyr/main.c +++ b/ports/zephyr/main.c @@ -92,7 +92,6 @@ int real_main(void) { upytest_set_heap(heap, heap + sizeof(heap)); int r = tinytest_main(1, argv, groups); printf("status: %d\n", r); - return 0; #endif soft_reset: From 080b0be1c8c6021126a6735af12f2c6909f1b01d Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 8 May 2017 19:28:38 +0300 Subject: [PATCH 679/828] zephyr/mpconfigport.h: Enable uhashlib and ubinascii modules. To be able to use data integrity checks in various tests. --- ports/zephyr/mpconfigport.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/zephyr/mpconfigport.h b/ports/zephyr/mpconfigport.h index 7ff05f45a8..5f5a5c3d24 100644 --- a/ports/zephyr/mpconfigport.h +++ b/ports/zephyr/mpconfigport.h @@ -67,6 +67,8 @@ #define MICROPY_PY_UERRNO (1) #define MICROPY_PY_USOCKET (1) #endif +#define MICROPY_PY_UBINASCII (1) +#define MICROPY_PY_UHASHLIB (1) #define MICROPY_PY_UTIME (1) #define MICROPY_PY_UTIME_MP_HAL (1) #define MICROPY_PY_ZEPHYR (1) From 0e52ee957df7700e27fe5bb2378b24b4cecfab08 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 16 Jan 2018 16:29:54 +0200 Subject: [PATCH 680/828] zephyr/modzsensor: Zephyr sensor subsystem bindings. --- ports/zephyr/Makefile | 1 + ports/zephyr/modzsensor.c | 146 ++++++++++++++++++++++++++++++++++++ ports/zephyr/mpconfigport.h | 9 +++ ports/zephyr/prj_base.conf | 4 + 4 files changed, 160 insertions(+) create mode 100644 ports/zephyr/modzsensor.c diff --git a/ports/zephyr/Makefile b/ports/zephyr/Makefile index 49a6f67188..04d067c817 100644 --- a/ports/zephyr/Makefile +++ b/ports/zephyr/Makefile @@ -41,6 +41,7 @@ SRC_C = main.c \ modusocket.c \ modutime.c \ modzephyr.c \ + modzsensor.c \ modmachine.c \ machine_pin.c \ uart_core.c \ diff --git a/ports/zephyr/modzsensor.c b/ports/zephyr/modzsensor.c new file mode 100644 index 0000000000..74c909d167 --- /dev/null +++ b/ports/zephyr/modzsensor.c @@ -0,0 +1,146 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" + +#include +#include + +#if MICROPY_PY_ZSENSOR + +typedef struct _mp_obj_sensor_t { + mp_obj_base_t base; + struct device *dev; +} mp_obj_sensor_t; + +STATIC mp_obj_t sensor_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + mp_obj_sensor_t *o = m_new_obj(mp_obj_sensor_t); + o->base.type = type; + o->dev = device_get_binding(mp_obj_str_get_str(args[0])); + if (o->dev == NULL) { + mp_raise_ValueError("dev not found"); + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t sensor_measure(mp_obj_t self_in) { + mp_obj_sensor_t *self = MP_OBJ_TO_PTR(self_in); + int st = sensor_sample_fetch(self->dev); + if (st != 0) { + mp_raise_OSError(-st); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(sensor_measure_obj, sensor_measure); + +STATIC void sensor_get_internal(mp_obj_t self_in, mp_obj_t channel_in, struct sensor_value *res) { + mp_obj_sensor_t *self = MP_OBJ_TO_PTR(self_in); + + int st = sensor_channel_get(self->dev, mp_obj_get_int(channel_in), res); + if (st != 0) { + mp_raise_OSError(-st); + } +} + +STATIC mp_obj_t sensor_get_float(mp_obj_t self_in, mp_obj_t channel_in) { + struct sensor_value val; + sensor_get_internal(self_in, channel_in, &val); + return mp_obj_new_float(val.val1 + (mp_float_t)val.val2 / 1000000); +} +MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_float_obj, sensor_get_float); + +STATIC mp_obj_t sensor_get_micros(mp_obj_t self_in, mp_obj_t channel_in) { + struct sensor_value val; + sensor_get_internal(self_in, channel_in, &val); + return MP_OBJ_NEW_SMALL_INT(val.val1 * 1000000 + val.val2); +} +MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_micros_obj, sensor_get_micros); + +STATIC mp_obj_t sensor_get_millis(mp_obj_t self_in, mp_obj_t channel_in) { + struct sensor_value val; + sensor_get_internal(self_in, channel_in, &val); + return MP_OBJ_NEW_SMALL_INT(val.val1 * 1000 + val.val2 / 1000); +} +MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_millis_obj, sensor_get_millis); + +STATIC mp_obj_t sensor_get_int(mp_obj_t self_in, mp_obj_t channel_in) { + struct sensor_value val; + sensor_get_internal(self_in, channel_in, &val); + return MP_OBJ_NEW_SMALL_INT(val.val1); +} +MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_int_obj, sensor_get_int); + +STATIC const mp_rom_map_elem_t sensor_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_measure), MP_ROM_PTR(&sensor_measure_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_float), MP_ROM_PTR(&sensor_get_float_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_micros), MP_ROM_PTR(&sensor_get_micros_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_millis), MP_ROM_PTR(&sensor_get_millis_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_int), MP_ROM_PTR(&sensor_get_int_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(sensor_locals_dict, sensor_locals_dict_table); + +STATIC const mp_obj_type_t sensor_type = { + { &mp_type_type }, + .name = MP_QSTR_Sensor, + .make_new = sensor_make_new, + .locals_dict = (void*)&sensor_locals_dict, +}; + +STATIC const mp_rom_map_elem_t mp_module_zsensor_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_zsensor) }, + { MP_ROM_QSTR(MP_QSTR_Sensor), MP_ROM_PTR(&sensor_type) }, + +#define C(name) { MP_ROM_QSTR(MP_QSTR_ ## name), MP_ROM_INT(SENSOR_CHAN_ ## name) } + C(ACCEL_X), + C(ACCEL_Y), + C(ACCEL_Z), + C(GYRO_X), + C(GYRO_Y), + C(GYRO_Z), + C(MAGN_X), + C(MAGN_Y), + C(MAGN_Z), + C(TEMP), + C(PRESS), + C(PROX), + C(HUMIDITY), + C(LIGHT), + C(ALTITUDE), +#undef C +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_zsensor_globals, mp_module_zsensor_globals_table); + +const mp_obj_module_t mp_module_zsensor = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_zsensor_globals, +}; + +#endif //MICROPY_PY_UHASHLIB diff --git a/ports/zephyr/mpconfigport.h b/ports/zephyr/mpconfigport.h index 5f5a5c3d24..1ac1c35013 100644 --- a/ports/zephyr/mpconfigport.h +++ b/ports/zephyr/mpconfigport.h @@ -72,6 +72,7 @@ #define MICROPY_PY_UTIME (1) #define MICROPY_PY_UTIME_MP_HAL (1) #define MICROPY_PY_ZEPHYR (1) +#define MICROPY_PY_ZSENSOR (1) #define MICROPY_PY_SYS_MODULES (0) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) @@ -111,6 +112,7 @@ extern const struct _mp_obj_module_t mp_module_machine; extern const struct _mp_obj_module_t mp_module_time; extern const struct _mp_obj_module_t mp_module_usocket; extern const struct _mp_obj_module_t mp_module_zephyr; +extern const struct _mp_obj_module_t mp_module_zsensor; #if MICROPY_PY_USOCKET #define MICROPY_PY_USOCKET_DEF { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_usocket) }, @@ -132,11 +134,18 @@ extern const struct _mp_obj_module_t mp_module_zephyr; #define MICROPY_PY_ZEPHYR_DEF #endif +#if MICROPY_PY_ZSENSOR +#define MICROPY_PY_ZSENSOR_DEF { MP_ROM_QSTR(MP_QSTR_zsensor), MP_ROM_PTR(&mp_module_zsensor) }, +#else +#define MICROPY_PY_ZSENSOR_DEF +#endif + #define MICROPY_PORT_BUILTIN_MODULES \ { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&mp_module_machine) }, \ MICROPY_PY_USOCKET_DEF \ MICROPY_PY_UTIME_DEF \ MICROPY_PY_ZEPHYR_DEF \ + MICROPY_PY_ZSENSOR_DEF \ #define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_time) }, \ diff --git a/ports/zephyr/prj_base.conf b/ports/zephyr/prj_base.conf index 3858c0a024..db6a1e3c11 100644 --- a/ports/zephyr/prj_base.conf +++ b/ports/zephyr/prj_base.conf @@ -14,6 +14,10 @@ CONFIG_NEWLIB_LIBC=y CONFIG_FLOAT=y CONFIG_MAIN_STACK_SIZE=4736 +# Enable sensor subsystem (doesn't add code if not used). +# Specific sensors should be enabled per-board. +CONFIG_SENSOR=y + # Networking config CONFIG_NETWORKING=y CONFIG_NET_IPV4=y From 7afbc498636be676f309193be50c1c47a700b157 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 23 Jan 2018 21:28:57 +0200 Subject: [PATCH 681/828] zephyr/prj_base.conf: Enable DHCP and group static IPs together. Add CONFIG_NET_DHCPV4, which, after https://github.com/zephyrproject-rtos/zephyr/pull/5750 works as follows: static addresses are configured after boot, and DHCP requests are sent at the same time. If valid DHCP reply is received, it overrides static addresses. This setup works out of the box for both direct connection to a workstation (DHCP server usually is not available) and for connection to a router (DHCP is available and required). --- ports/zephyr/prj_base.conf | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ports/zephyr/prj_base.conf b/ports/zephyr/prj_base.conf index db6a1e3c11..c39779548f 100644 --- a/ports/zephyr/prj_base.conf +++ b/ports/zephyr/prj_base.conf @@ -32,16 +32,22 @@ CONFIG_NET_APP_SETTINGS=y CONFIG_NET_APP_INIT_TIMEOUT=3 CONFIG_NET_APP_NEED_IPV6=y CONFIG_NET_APP_NEED_IPV4=y -CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1" -CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1" -CONFIG_NET_APP_MY_IPV4_GW="192.0.2.2" # DNS CONFIG_DNS_RESOLVER=y CONFIG_DNS_RESOLVER_ADDITIONAL_QUERIES=2 CONFIG_DNS_SERVER_IP_ADDRESSES=y + +# Static IP addresses +CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1" +CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1" +CONFIG_NET_APP_MY_IPV4_GW="192.0.2.2" CONFIG_DNS_SERVER1="192.0.2.2" +# DHCP configuration. Until DHCP address is assigned, +# static configuration above is used instead. +CONFIG_NET_DHCPV4=y + # Diagnostics and debugging # Required for zephyr.stack_analyze() From 5a023372df68bc3a210d0a7ae12363e82270e705 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 19 Jan 2018 12:17:09 +0200 Subject: [PATCH 682/828] zephyr: Add prj_disco_l475_iot1.conf with sensor drivers. --- ports/zephyr/prj_disco_l475_iot1.conf | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 ports/zephyr/prj_disco_l475_iot1.conf diff --git a/ports/zephyr/prj_disco_l475_iot1.conf b/ports/zephyr/prj_disco_l475_iot1.conf new file mode 100644 index 0000000000..36c8b99ddb --- /dev/null +++ b/ports/zephyr/prj_disco_l475_iot1.conf @@ -0,0 +1,5 @@ +# Sensors +CONFIG_HTS221=y +CONFIG_LIS3MDL=y +CONFIG_LPS22HB=y +CONFIG_LSM6DSL=y From 478410b4091406b66bfa220ab92465e5e08134a2 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 2 May 2018 15:22:47 +0300 Subject: [PATCH 683/828] zephyr/Makefile: Add kobj_types_h_target to Z_EXPORTS. New generated Zephyr header file, without it build breaks. --- ports/zephyr/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr/Makefile b/ports/zephyr/Makefile index 04d067c817..8cb4c12ef7 100644 --- a/ports/zephyr/Makefile +++ b/ports/zephyr/Makefile @@ -106,4 +106,4 @@ outdir/$(BOARD)/Makefile: $(CONF_FILE) $(Z_EXPORTS): outdir/$(BOARD)/Makefile make --no-print-directory -C outdir/$(BOARD) outputexports CMAKE_COMMAND=: >$@ - make -C outdir/$(BOARD) syscall_macros_h_target syscall_list_h_target + make -C outdir/$(BOARD) syscall_macros_h_target syscall_list_h_target kobj_types_h_target From 2923671a0cd62f370a2b33bbd52354c7b5624300 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 21 May 2018 11:28:36 +1000 Subject: [PATCH 684/828] esp32/Makefile: Update to latest ESP IDF version. --- ports/esp32/Makefile | 146 ++++++++++++++++++++++--------------------- 1 file changed, 74 insertions(+), 72 deletions(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 304082df9d..c8e2f67d39 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -21,7 +21,7 @@ FLASH_FREQ ?= 40m FLASH_SIZE ?= 4MB CROSS_COMPILE ?= xtensa-esp32-elf- -ESPIDF_SUPHASH := a2556229aa6f55b16b171e3325ee9ab1943e8552 +ESPIDF_SUPHASH := 1f7b41e206646417adc572da928175d33c986bd3 # paths to ESP IDF and its components ifeq ($(ESPIDF),) @@ -80,7 +80,7 @@ INC_ESPCOMP += -I$(ESPCOMP)/tcpip_adapter/include INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip/port INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip/posix -INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/include +INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/mbedtls/include INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/port/include INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/include INC_ESPCOMP += -I$(ESPCOMP)/ulp/include @@ -369,6 +369,7 @@ ESPIDF_APP_UPDATE_O = $(addprefix $(ESPCOMP)/app_update/,\ ESPIDF_NEWLIB_O = $(addprefix $(ESPCOMP)/newlib/,\ time.o \ + select.o \ syscalls.o \ syscall_table.o \ reent_init.o \ @@ -482,75 +483,76 @@ ESPIDF_LWIP_O = $(addprefix $(ESPCOMP)/lwip/,\ ) ESPIDF_MBEDTLS_O = $(addprefix $(ESPCOMP)/mbedtls/,\ - library/entropy.o \ - library/pkcs12.o \ - library/ccm.o \ - library/pk.o \ - library/sha1.o \ - library/x509_csr.o \ - library/ssl_cli.o \ - library/ecp.o \ - library/blowfish.o \ - library/x509.o \ - library/ecp_curves.o \ - library/error.o \ - library/ssl_ticket.o \ - library/entropy_poll.o \ - library/cipher.o \ - library/version_features.o \ - library/ripemd160.o \ - library/rsa.o \ - library/md.o \ - library/md_wrap.o \ - library/sha256.o \ - library/dhm.o \ - library/ssl_cache.o \ - library/pkwrite.o \ - library/base64.o \ - library/asn1parse.o \ - library/ssl_tls.o \ - library/hmac_drbg.o \ - library/pem.o \ - library/version.o \ - library/gcm.o \ - library/memory_buffer_alloc.o \ - library/md2.o \ - library/ecdsa.o \ - library/ssl_srv.o \ - library/x509_crt.o \ - library/ecdh.o \ - library/asn1write.o \ - library/md4.o \ - library/debug.o \ - library/x509_create.o \ - library/ecjpake.o \ - library/oid.o \ - library/md5.o \ - library/ssl_ciphersuites.o \ - library/sha512.o \ - library/xtea.o \ - library/aes.o \ - library/cipher_wrap.o \ - library/arc4.o \ - library/bignum.o \ - library/pkparse.o \ - library/padlock.o \ - library/threading.o \ - library/x509_crl.o \ - library/pkcs11.o \ - library/aesni.o \ - library/timing.o \ - library/certs.o \ - library/pkcs5.o \ - library/ssl_cookie.o \ - library/camellia.o \ - library/havege.o \ - library/des.o \ - library/x509write_csr.o \ - library/platform.o \ - library/ctr_drbg.o \ - library/x509write_crt.o \ - library/pk_wrap.o \ + mbedtls/library/entropy.o \ + mbedtls/library/pkcs12.o \ + mbedtls/library/ccm.o \ + mbedtls/library/pk.o \ + mbedtls/library/sha1.o \ + mbedtls/library/x509_csr.o \ + mbedtls/library/ssl_cli.o \ + mbedtls/library/ecp.o \ + mbedtls/library/blowfish.o \ + mbedtls/library/x509.o \ + mbedtls/library/ecp_curves.o \ + mbedtls/library/error.o \ + mbedtls/library/ssl_ticket.o \ + mbedtls/library/entropy_poll.o \ + mbedtls/library/cipher.o \ + mbedtls/library/version_features.o \ + mbedtls/library/ripemd160.o \ + mbedtls/library/rsa.o \ + mbedtls/library/rsa_internal.o \ + mbedtls/library/md.o \ + mbedtls/library/md_wrap.o \ + mbedtls/library/sha256.o \ + mbedtls/library/dhm.o \ + mbedtls/library/ssl_cache.o \ + mbedtls/library/pkwrite.o \ + mbedtls/library/base64.o \ + mbedtls/library/asn1parse.o \ + mbedtls/library/ssl_tls.o \ + mbedtls/library/hmac_drbg.o \ + mbedtls/library/pem.o \ + mbedtls/library/version.o \ + mbedtls/library/gcm.o \ + mbedtls/library/memory_buffer_alloc.o \ + mbedtls/library/md2.o \ + mbedtls/library/ecdsa.o \ + mbedtls/library/ssl_srv.o \ + mbedtls/library/x509_crt.o \ + mbedtls/library/ecdh.o \ + mbedtls/library/asn1write.o \ + mbedtls/library/md4.o \ + mbedtls/library/debug.o \ + mbedtls/library/x509_create.o \ + mbedtls/library/ecjpake.o \ + mbedtls/library/oid.o \ + mbedtls/library/md5.o \ + mbedtls/library/ssl_ciphersuites.o \ + mbedtls/library/sha512.o \ + mbedtls/library/xtea.o \ + mbedtls/library/aes.o \ + mbedtls/library/cipher_wrap.o \ + mbedtls/library/arc4.o \ + mbedtls/library/bignum.o \ + mbedtls/library/pkparse.o \ + mbedtls/library/padlock.o \ + mbedtls/library/threading.o \ + mbedtls/library/x509_crl.o \ + mbedtls/library/pkcs11.o \ + mbedtls/library/aesni.o \ + mbedtls/library/timing.o \ + mbedtls/library/certs.o \ + mbedtls/library/pkcs5.o \ + mbedtls/library/ssl_cookie.o \ + mbedtls/library/camellia.o \ + mbedtls/library/havege.o \ + mbedtls/library/des.o \ + mbedtls/library/x509write_csr.o \ + mbedtls/library/platform.o \ + mbedtls/library/ctr_drbg.o \ + mbedtls/library/x509write_crt.o \ + mbedtls/library/pk_wrap.o \ port/esp_bignum.o \ port/esp_hardware.o \ port/esp_sha1.o \ @@ -558,7 +560,7 @@ ESPIDF_MBEDTLS_O = $(addprefix $(ESPCOMP)/mbedtls/,\ port/esp_sha512.o \ ) -$(BUILD)/$(ESPCOMP)/wpa_supplicant/%.o: CFLAGS += -DEMBEDDED_SUPP -D__ets__ -Wno-strict-aliasing +$(BUILD)/$(ESPCOMP)/wpa_supplicant/%.o: CFLAGS += -DEMBEDDED_SUPP -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_MSCHAPv2 -DEAP_TTLS -DEAP_TLS -DEAP_PEAP -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -D__ets__ -Wno-strict-aliasing ESPIDF_WPA_SUPPLICANT_O = $(addprefix $(ESPCOMP)/wpa_supplicant/,\ src/crypto/aes-internal-enc.o \ src/crypto/sha256-internal.o \ From afd0701bf7a9dcb50c5ab46b0ae88b303fec6ed3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 15 May 2018 15:13:58 +1000 Subject: [PATCH 685/828] esp8266: Change UART(0) to attach to REPL via uos.dupterm interface. This patch makes it so that UART(0) can by dynamically attached to and detached from the REPL by using the uos.dupterm function. Since WebREPL uses dupterm slot 0 the UART uses dupterm slot 1 (a slot which is newly introduced by this patch). UART(0) must now be attached manually in boot.py (or otherwise) and inisetup.py is changed to provide code to do this. For example, to attach use: import uos, machine uart = machine.UART(0, 115200) uos.dupterm(uart, 1) and to detach use: uos.dupterm(None, 1) When attached, all incoming chars on UART(0) go straight to stdin so uart.read() will always return None. Use sys.stdin.read() if it's needed to read characters from the UART(0) while it's also used for the REPL (or detach, read, then reattach). When detached the UART(0) can be used for other purposes. If there are no objects in any of the dupterm slots when the REPL is started (on hard or soft reset) then UART(0) is automatically attached. Without this, the only way to recover a board without a REPL would be to completely erase and reflash (which would install the default boot.py which attaches the REPL). --- ports/esp8266/esp_mphal.c | 27 ++++++++++----------------- ports/esp8266/esp_mphal.h | 7 +++++-- ports/esp8266/main.c | 20 ++++++++++++++++++++ ports/esp8266/modules/inisetup.py | 2 ++ ports/esp8266/moduos.c | 15 ++++++++++++++- ports/esp8266/mpconfigport.h | 2 +- ports/esp8266/uart.c | 29 +++++++++++++++++++++-------- 7 files changed, 73 insertions(+), 29 deletions(-) diff --git a/ports/esp8266/esp_mphal.c b/ports/esp8266/esp_mphal.c index 9f4f051fdd..df97a73430 100644 --- a/ports/esp8266/esp_mphal.c +++ b/ports/esp8266/esp_mphal.c @@ -35,15 +35,18 @@ #include "extmod/misc.h" #include "lib/utils/pyexec.h" -STATIC byte input_buf_array[256]; -ringbuf_t input_buf = {input_buf_array, sizeof(input_buf_array)}; +STATIC byte stdin_ringbuf_array[256]; +ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0}; void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len); const mp_print_t mp_debug_print = {NULL, mp_hal_debug_tx_strn_cooked}; +int uart_attached_to_dupterm; + void mp_hal_init(void) { //ets_wdt_disable(); // it's a pain while developing mp_hal_rtc_init(); uart_init(UART_BIT_RATE_115200, UART_BIT_RATE_115200); + uart_attached_to_dupterm = 0; } void mp_hal_delay_us(uint32_t us) { @@ -55,7 +58,7 @@ void mp_hal_delay_us(uint32_t us) { int mp_hal_stdin_rx_chr(void) { for (;;) { - int c = ringbuf_get(&input_buf); + int c = ringbuf_get(&stdin_ringbuf); if (c != -1) { return c; } @@ -80,19 +83,11 @@ void mp_hal_debug_str(const char *str) { #endif void mp_hal_stdout_tx_str(const char *str) { - const char *last = str; - while (*str) { - uart_tx_one_char(UART0, *str++); - } - mp_uos_dupterm_tx_strn(last, str - last); + mp_uos_dupterm_tx_strn(str, strlen(str)); } void mp_hal_stdout_tx_strn(const char *str, uint32_t len) { - const char *last = str; - while (len--) { - uart_tx_one_char(UART0, *str++); - } - mp_uos_dupterm_tx_strn(last, str - last); + mp_uos_dupterm_tx_strn(str, len); } void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) { @@ -102,13 +97,11 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) { if (str > last) { mp_uos_dupterm_tx_strn(last, str - last); } - uart_tx_one_char(UART0, '\r'); - uart_tx_one_char(UART0, '\n'); mp_uos_dupterm_tx_strn("\r\n", 2); ++str; last = str; } else { - uart_tx_one_char(UART0, *str++); + ++str; } } if (str > last) { @@ -166,7 +159,7 @@ STATIC void dupterm_task_handler(os_event_t *evt) { if (c < 0) { break; } - ringbuf_put(&input_buf, c); + ringbuf_put(&stdin_ringbuf, c); } mp_hal_signal_input(); lock = 0; diff --git a/ports/esp8266/esp_mphal.h b/ports/esp8266/esp_mphal.h index 940ca47271..56d9fa35fe 100644 --- a/ports/esp8266/esp_mphal.h +++ b/ports/esp8266/esp_mphal.h @@ -34,12 +34,15 @@ struct _mp_print_t; // Structure for UART-only output via mp_printf() extern const struct _mp_print_t mp_debug_print; -extern ringbuf_t input_buf; -// Call this after putting data to input_buf +extern ringbuf_t stdin_ringbuf; +// Call this after putting data to stdin_ringbuf void mp_hal_signal_input(void); // Call this when data is available in dupterm object void mp_hal_signal_dupterm_input(void); +// This variable counts how many times the UART is attached to dupterm +extern int uart_attached_to_dupterm; + void mp_hal_init(void); void mp_hal_rtc_init(void); diff --git a/ports/esp8266/main.c b/ports/esp8266/main.c index d2d2c34ece..975262fd16 100644 --- a/ports/esp8266/main.c +++ b/ports/esp8266/main.c @@ -33,6 +33,7 @@ #include "py/mperrno.h" #include "py/mphal.h" #include "py/gc.h" +#include "extmod/misc.h" #include "lib/mp-readline/readline.h" #include "lib/utils/pyexec.h" #include "gccollect.h" @@ -65,6 +66,25 @@ STATIC void mp_reset(void) { pyexec_file("main.py"); } #endif + + // Check if there are any dupterm objects registered and if not then + // activate UART(0), or else there will never be any chance to get a REPL + size_t idx; + for (idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) { + if (MP_STATE_VM(dupterm_objs[idx]) != MP_OBJ_NULL) { + break; + } + } + if (idx == MICROPY_PY_OS_DUPTERM) { + mp_obj_t args[2]; + args[0] = MP_OBJ_NEW_SMALL_INT(0); + args[1] = MP_OBJ_NEW_SMALL_INT(115200); + args[0] = pyb_uart_type.make_new(&pyb_uart_type, 2, 0, args); + args[1] = MP_OBJ_NEW_SMALL_INT(1); + extern mp_obj_t os_dupterm(size_t n_args, const mp_obj_t *args); + os_dupterm(2, args); + mp_hal_stdout_tx_str("Activated UART(0) for REPL\r\n"); + } } void soft_reset(void) { diff --git a/ports/esp8266/modules/inisetup.py b/ports/esp8266/modules/inisetup.py index af78dfad51..9184c6c396 100644 --- a/ports/esp8266/modules/inisetup.py +++ b/ports/esp8266/modules/inisetup.py @@ -44,6 +44,8 @@ def setup(): # This file is executed on every boot (including wake-boot from deepsleep) #import esp #esp.osdebug(None) +import uos, machine +uos.dupterm(machine.UART(0, 115200), 1) import gc #import webrepl #webrepl.start() diff --git a/ports/esp8266/moduos.c b/ports/esp8266/moduos.c index 93f7aa712d..7a32c11c07 100644 --- a/ports/esp8266/moduos.c +++ b/ports/esp8266/moduos.c @@ -76,6 +76,19 @@ STATIC mp_obj_t os_urandom(mp_obj_t num) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); +// We wrap the mp_uos_dupterm function to detect if a UART is attached or not +mp_obj_t os_dupterm(size_t n_args, const mp_obj_t *args) { + mp_obj_t prev_obj = mp_uos_dupterm_obj.fun.var(n_args, args); + if (mp_obj_get_type(args[0]) == &pyb_uart_type) { + ++uart_attached_to_dupterm; + } + if (mp_obj_get_type(prev_obj) == &pyb_uart_type) { + --uart_attached_to_dupterm; + } + return prev_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_dupterm_obj, 1, 2, os_dupterm); + STATIC mp_obj_t os_dupterm_notify(mp_obj_t obj_in) { (void)obj_in; mp_hal_signal_dupterm_input(); @@ -88,7 +101,7 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) }, { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) }, #if MICROPY_PY_OS_DUPTERM - { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) }, + { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&os_dupterm_obj) }, { MP_ROM_QSTR(MP_QSTR_dupterm_notify), MP_ROM_PTR(&os_dupterm_notify_obj) }, #endif #if MICROPY_VFS_FAT diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index 8de28eb96e..ec347dae08 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -86,7 +86,7 @@ #define MICROPY_PY_WEBREPL_DELAY (20) #define MICROPY_PY_FRAMEBUF (1) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) -#define MICROPY_PY_OS_DUPTERM (1) +#define MICROPY_PY_OS_DUPTERM (2) #define MICROPY_CPYTHON_COMPAT (1) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) diff --git a/ports/esp8266/uart.c b/ports/esp8266/uart.c index ec944a97cc..52707f9812 100644 --- a/ports/esp8266/uart.c +++ b/ports/esp8266/uart.c @@ -34,6 +34,11 @@ static int uart_os = UART_OS; static os_event_t uart_evt_queue[16]; #endif +// A small, static ring buffer for incoming chars +// This will only be populated if the UART is not attached to dupterm +static byte uart_ringbuf_array[16]; +static ringbuf_t uart_ringbuf = {uart_ringbuf_array, sizeof(uart_ringbuf_array), 0, 0}; + static void uart0_rx_intr_handler(void *para); void soft_reset(void); @@ -170,18 +175,26 @@ static void uart0_rx_intr_handler(void *para) { while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) { uint8 RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff; - if (RcvChar == mp_interrupt_char) { - mp_keyboard_interrupt(); + // For efficiency, when connected to dupterm we put incoming chars + // directly on stdin_ringbuf, rather than going via uart_ringbuf + if (uart_attached_to_dupterm) { + if (RcvChar == mp_interrupt_char) { + mp_keyboard_interrupt(); + } else { + ringbuf_put(&stdin_ringbuf, RcvChar); + } } else { - ringbuf_put(&input_buf, RcvChar); + ringbuf_put(&uart_ringbuf, RcvChar); } } - mp_hal_signal_input(); - // Clear pending FIFO interrupts WRITE_PERI_REG(UART_INT_CLR(UART_REPL), UART_RXFIFO_TOUT_INT_CLR | UART_RXFIFO_FULL_INT_ST); ETS_UART_INTR_ENABLE(); + + if (uart_attached_to_dupterm) { + mp_hal_signal_input(); + } } } @@ -190,7 +203,7 @@ static void uart0_rx_intr_handler(void *para) { bool uart_rx_wait(uint32_t timeout_us) { uint32_t start = system_get_time(); for (;;) { - if (input_buf.iget != input_buf.iput) { + if (uart_ringbuf.iget != uart_ringbuf.iput) { return true; // have at least 1 char ready for reading } if (system_get_time() - start >= timeout_us) { @@ -201,7 +214,7 @@ bool uart_rx_wait(uint32_t timeout_us) { } int uart_rx_any(uint8 uart) { - if (input_buf.iget != input_buf.iput) { + if (uart_ringbuf.iget != uart_ringbuf.iput) { return true; // have at least 1 char ready for reading } return false; @@ -217,7 +230,7 @@ int uart_tx_any_room(uint8 uart) { // Returns char from the input buffer, else -1 if buffer is empty. int uart_rx_char(void) { - return ringbuf_get(&input_buf); + return ringbuf_get(&uart_ringbuf); } int uart_rx_one_char(uint8 uart_no) { From bc6c0b28bf830a75c817fb498b713779c92b731b Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 19 May 2018 10:52:43 -0500 Subject: [PATCH 686/828] py/emitbc: Avoid undefined behavior calling memset() with NULL 1st arg. Calling memset(NULL, value, 0) is not standards compliant so we must add an explicit check that emit->label_offsets is indeed not NULL before calling memset (this pointer will be NULL on the first pass of the parse tree and it's more logical / safer to check this pointer rather than check that the pass is not the first one). Code sanitizers will warn if NULL is passed as the first value to memset, and compilers may optimise the code based on the knowledge that any pointer passed to memset is guaranteed not to be NULL. --- py/emitbc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/emitbc.c b/py/emitbc.c index 32e8330006..b1b61ba67e 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -315,7 +315,7 @@ void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { emit->last_source_line = 1; #ifndef NDEBUG // With debugging enabled labels are checked for unique assignment - if (pass < MP_PASS_EMIT) { + if (pass < MP_PASS_EMIT && emit->label_offsets != NULL) { memset(emit->label_offsets, -1, emit->max_num_labels * sizeof(mp_uint_t)); } #endif From 5efc575067df17be785d2b60124706d789d6cfe0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 21 May 2018 12:27:38 +1000 Subject: [PATCH 687/828] py/parsenum: Use int instead of mp_int_t for parsing float exponent. There is no need to use the mp_int_t type which may be 64-bits wide, there is enough bit-width in a normal int to parse reasonable exponents. Using int helps to reduce code size for 64-bit ports, especially nan-boxing builds. (Similarly for the "dig" variable which is now an unsigned int.) --- py/parsenum.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/py/parsenum.c b/py/parsenum.c index 124489c66e..8bd5232eb4 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -227,10 +227,10 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool // string should be a decimal number parse_dec_in_t in = PARSE_DEC_IN_INTG; bool exp_neg = false; - mp_int_t exp_val = 0; - mp_int_t exp_extra = 0; + int exp_val = 0; + int exp_extra = 0; while (str < top) { - mp_uint_t dig = *str++; + unsigned int dig = *str++; if ('0' <= dig && dig <= '9') { dig -= '0'; if (in == PARSE_DEC_IN_EXP) { From 4f71a2a75a71b89dad2eed147d6e237b633b878e Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 19 May 2018 10:56:34 -0500 Subject: [PATCH 688/828] py/parsenum: Avoid undefined behavior parsing floats with large exponents. Fuzz testing combined with the undefined behavior sanitizer found that parsing unreasonable float literals like 1e+9999999999999 resulted in undefined behavior due to overflow in signed integer arithmetic, and a wrong result being returned. --- py/parsenum.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/py/parsenum.c b/py/parsenum.c index 8bd5232eb4..ba7e40afd6 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -234,7 +234,12 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool if ('0' <= dig && dig <= '9') { dig -= '0'; if (in == PARSE_DEC_IN_EXP) { - exp_val = 10 * exp_val + dig; + // don't overflow exp_val when adding next digit, instead just truncate + // it and the resulting float will still be correct, either inf or 0.0 + // (use INT_MAX/2 to allow adding exp_extra at the end without overflow) + if (exp_val < (INT_MAX / 2 - 9) / 10) { + exp_val = 10 * exp_val + dig; + } } else { if (dec_val < DEC_VAL_MAX) { // dec_val won't overflow so keep accumulating From 60eb5305f637e21f7ec4006924c06518ca6de476 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 19 May 2018 11:25:03 -0500 Subject: [PATCH 689/828] py/objfloat: Fix undefined shifting behavior in high-quality float hash. When computing e.g. hash(0.4e3) with ubsan enabled, a diagnostic like the following would occur: ../../py/objfloat.c:91:30: runtime error: shift exponent 44 is too large for 32-bit type 'int' By casting constant "1" to the right type the intended value is preserved. --- py/objfloat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/objfloat.c b/py/objfloat.c index e4d5a65701..31c624778f 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -88,7 +88,7 @@ typedef uint32_t mp_float_uint_t; if (adj_exp <= MP_FLOAT_FRAC_BITS) { // number may have a fraction; xor the integer part with the fractional part val = (frc >> (MP_FLOAT_FRAC_BITS - adj_exp)) - ^ (frc & ((1 << (MP_FLOAT_FRAC_BITS - adj_exp)) - 1)); + ^ (frc & (((mp_float_uint_t)1 << (MP_FLOAT_FRAC_BITS - adj_exp)) - 1)); } else if ((unsigned int)adj_exp < BITS_PER_BYTE * sizeof(mp_int_t) - 1) { // the number is a (big) whole integer and will fit in val's signed-width val = (mp_int_t)frc << (adj_exp - MP_FLOAT_FRAC_BITS); From c4dafcef4fe9edaacaeeb16c412c298cbab3b414 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 19 May 2018 11:20:29 -0500 Subject: [PATCH 690/828] py/mpz: Avoid undefined behavior at integer overflow in mpz_hash. Before this, ubsan would detect a problem when executing hash(006699999999999999999999999999999999999999999999999999999999999999999999) ../../py/mpz.c:1539:20: runtime error: left shift of 1067371580458 by 32 places cannot be represented in type 'mp_int_t' (aka 'long') When the overflow does occur it now happens as defined by the rules of unsigned arithmetic. --- py/mpz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/mpz.c b/py/mpz.c index fa50868620..8687092d02 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -1532,7 +1532,7 @@ mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs) { // must return actual int value if it fits in mp_int_t mp_int_t mpz_hash(const mpz_t *z) { - mp_int_t val = 0; + mp_uint_t val = 0; mpz_dig_t *d = z->dig + z->len; while (d-- > z->dig) { From 95e43efc994af7d7ff85ef1722eac163be9cc5fd Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 19 May 2018 13:13:02 -0500 Subject: [PATCH 691/828] py/objfloat: Fix undefined integer behavior hashing negative zero. Under ubsan, when evaluating hash(-0.) the following diagnostic occurs: ../../py/objfloat.c:102:15: runtime error: negation of -9223372036854775808 cannot be represented in type 'mp_int_t' (aka 'long'); cast to an unsigned type to negate this value to itself So do just that, to tell the compiler that we want to perform this operation using modulo arithmetic rules. --- py/objfloat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/objfloat.c b/py/objfloat.c index 31c624778f..b62fe8e71d 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -99,7 +99,7 @@ typedef uint32_t mp_float_uint_t; } if (u.p.sgn) { - val = -val; + val = -(mp_uint_t)val; } return val; From 1ad0013decb42418ca667c2d9994198b537fa778 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 21 May 2018 13:05:40 +1000 Subject: [PATCH 692/828] tests: Add some tests for bigint hash, float hash and float parsing. Following outcome of recent fuzz testing and sanitizing by @jepler. --- tests/basics/builtin_hash_intbig.py | 3 +++ tests/float/builtin_float_hash.py | 2 ++ tests/float/float_parse.py | 6 ++++++ 3 files changed, 11 insertions(+) diff --git a/tests/basics/builtin_hash_intbig.py b/tests/basics/builtin_hash_intbig.py index 0092c0f3ad..df51f72abb 100644 --- a/tests/basics/builtin_hash_intbig.py +++ b/tests/basics/builtin_hash_intbig.py @@ -8,3 +8,6 @@ class F: def __hash__(self): return 1 << 70 | 1 print(hash(F()) != 0) + +# this had a particular error with internal integer arithmetic of hash function +print(hash(6699999999999999999999999999999999999999999999999999999999999999999999) != 0) diff --git a/tests/float/builtin_float_hash.py b/tests/float/builtin_float_hash.py index dd184595f9..7a7e374010 100644 --- a/tests/float/builtin_float_hash.py +++ b/tests/float/builtin_float_hash.py @@ -3,6 +3,7 @@ # these should hash to an integer with a specific value for val in ( '0.0', + '-0.0', '1.0', '2.0', '-12.0', @@ -15,6 +16,7 @@ for val in ( '0.1', '-0.1', '10.3', + '0.4e3', '1e16', 'inf', '-inf', diff --git a/tests/float/float_parse.py b/tests/float/float_parse.py index ae6b114f03..4b026de1c8 100644 --- a/tests/float/float_parse.py +++ b/tests/float/float_parse.py @@ -24,3 +24,9 @@ print(float('.' + '0' * 60 + '9e40') == float('9e-21')) print(float('1.00000000000000000000e-37')) print(float('10.0000000000000000000e-38')) print(float('100.000000000000000000e-39')) + +# very large exponent literal +print(float('1e4294967301')) +print(float('1e-4294967301')) +print(float('1e18446744073709551621')) +print(float('1e-18446744073709551621')) From cac2eddc1634e65a1097646d11016298e6375f87 Mon Sep 17 00:00:00 2001 From: Daniel Shaulov Date: Sun, 20 May 2018 21:05:12 +0300 Subject: [PATCH 693/828] minimal/main: Allow to compile without GC enabled. --- ports/minimal/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/minimal/main.c b/ports/minimal/main.c index 9d43a9cf97..5e145dc829 100644 --- a/ports/minimal/main.c +++ b/ports/minimal/main.c @@ -27,7 +27,9 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) { #endif static char *stack_top; +#if MICROPY_ENABLE_GC static char heap[2048]; +#endif int main(int argc, char **argv) { int stack_dummy; From 6bd78741c13849da0570710ad6df80846df812c0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 21 May 2018 13:36:21 +1000 Subject: [PATCH 694/828] py/gc: When GC threshold is hit don't unnecessarily collect twice. Without this, if GC threshold is hit and there is not enough memory left to satisfy the request, gc_collect() will run a second time and the search for memory will happen again and will fail again. Thanks to @adritium for pointing out this issue, see #3786. --- py/gc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/py/gc.c b/py/gc.c index 38de513997..e92b81ece7 100644 --- a/py/gc.c +++ b/py/gc.c @@ -453,6 +453,7 @@ void *gc_alloc(size_t n_bytes, bool has_finaliser) { if (!collected && MP_STATE_MEM(gc_alloc_amount) >= MP_STATE_MEM(gc_alloc_threshold)) { GC_EXIT(); gc_collect(); + collected = 1; GC_ENTER(); } #endif From 6c955932f3c4bfa56336cbacad389d9f874cba10 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 21 May 2018 14:08:37 +1000 Subject: [PATCH 695/828] stm32/rtc: Don't try to set SubSeconds value on RTC. The hardware doesn't allow it, instead the value is reset to 255 upon setting the other calendar/time values. --- docs/library/pyb.RTC.rst | 2 +- ports/stm32/rtc.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/library/pyb.RTC.rst b/docs/library/pyb.RTC.rst index 2628554526..1a1df90951 100644 --- a/docs/library/pyb.RTC.rst +++ b/docs/library/pyb.RTC.rst @@ -31,7 +31,7 @@ Methods With no arguments, this method returns an 8-tuple with the current date and time. With 1 argument (being an 8-tuple) it sets the date - and time. + and time (and ``subseconds`` is reset to 255). .. only:: port_pyboard diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index 744fbe8b96..4134037124 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -529,7 +529,6 @@ mp_obj_t pyb_rtc_datetime(size_t n_args, const mp_obj_t *args) { time.Hours = mp_obj_get_int(items[4]); time.Minutes = mp_obj_get_int(items[5]); time.Seconds = mp_obj_get_int(items[6]); - time.SubSeconds = rtc_us_to_subsec(mp_obj_get_int(items[7])); time.TimeFormat = RTC_HOURFORMAT12_AM; time.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; time.StoreOperation = RTC_STOREOPERATION_SET; From 41766ba7e67022d2d15ce78896a730745ea3871f Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 21 May 2018 16:46:30 +1000 Subject: [PATCH 696/828] extmod/modlwip: Allow to compile with MICROPY_PY_LWIP disabled. --- extmod/modlwip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 7c0a20a1bf..dfb5de9e40 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -1409,7 +1409,7 @@ STATIC mp_obj_t lwip_getaddrinfo(size_t n_args, const mp_obj_t *args) { tuple->items[4] = netutils_format_inet_addr((uint8_t*)&state.ipaddr, port, NETUTILS_BIG); return mp_obj_new_list(1, (mp_obj_t*)&tuple); } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_getaddrinfo_obj, 2, 6, lwip_getaddrinfo); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_getaddrinfo_obj, 2, 6, lwip_getaddrinfo); // Debug functions From cda964198a36e8d1ce4497d90484fae4b9d661a5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 21 May 2018 16:48:24 +1000 Subject: [PATCH 697/828] stm32: Integrate lwIP as implementation of usocket module. This patch allows to use lwIP as the implementation of the usocket module, instead of the existing socket-multiplexer that delegates the entire TCP/IP layer to the NIC itself. This is disabled by default, and enabled by defining MICROPY_PY_LWIP to 1. When enabled, the lwIP TCP/IP stack will be included in the build with default settings for memory usage and performance (see lwip_inc/lwipopts.h). It is then up to a particular NIC to register itself with lwIP using the standard lwIP netif API. --- ports/stm32/Makefile | 42 +++++++++++++++++++ ports/stm32/lwip_inc/arch/cc.h | 8 ++++ ports/stm32/lwip_inc/arch/sys_arch.h | 1 + ports/stm32/lwip_inc/lwipopts.h | 61 ++++++++++++++++++++++++++++ ports/stm32/main.c | 10 +++++ ports/stm32/modnetwork.c | 33 +++++++++++++++ ports/stm32/modnetwork.h | 14 +++++++ ports/stm32/modusocket.c | 4 +- ports/stm32/mpconfigport.h | 13 +++++- 9 files changed, 183 insertions(+), 3 deletions(-) create mode 100644 ports/stm32/lwip_inc/arch/cc.h create mode 100644 ports/stm32/lwip_inc/arch/sys_arch.h create mode 100644 ports/stm32/lwip_inc/lwipopts.h diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 99e2995ffb..cbfd8baa1a 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -184,6 +184,7 @@ SRC_LIBM = $(addprefix lib/libm/,\ endif EXTMOD_SRC_C = $(addprefix extmod/,\ + modlwip.c \ modonewire.c \ ) @@ -337,6 +338,47 @@ SRC_MOD += $(addprefix $(CC3000_DIR)/src/,\ ) endif +LWIP_DIR = lib/lwip/src +INC += -I$(TOP)/$(LWIP_DIR)/include -Ilwip_inc +$(BUILD)/$(LWIP_DIR)/core/ipv4/dhcp.o: CFLAGS += -Wno-address +SRC_MOD += $(addprefix $(LWIP_DIR)/,\ + core/def.c \ + core/dns.c \ + core/inet_chksum.c \ + core/init.c \ + core/ip.c \ + core/mem.c \ + core/memp.c \ + core/netif.c \ + core/pbuf.c \ + core/raw.c \ + core/stats.c \ + core/sys.c \ + core/tcp.c \ + core/tcp_in.c \ + core/tcp_out.c \ + core/timeouts.c \ + core/udp.c \ + core/ipv4/autoip.c \ + core/ipv4/dhcp.c \ + core/ipv4/etharp.c \ + core/ipv4/icmp.c \ + core/ipv4/igmp.c \ + core/ipv4/ip4_addr.c \ + core/ipv4/ip4.c \ + core/ipv4/ip4_frag.c \ + core/ipv6/dhcp6.c \ + core/ipv6/ethip6.c \ + core/ipv6/icmp6.c \ + core/ipv6/inet6.c \ + core/ipv6/ip6_addr.c \ + core/ipv6/ip6.c \ + core/ipv6/ip6_frag.c \ + core/ipv6/mld6.c \ + core/ipv6/nd6.c \ + netif/ethernet.c \ + ) + OBJ = OBJ += $(PY_O) OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o)) diff --git a/ports/stm32/lwip_inc/arch/cc.h b/ports/stm32/lwip_inc/arch/cc.h new file mode 100644 index 0000000000..635b1c8056 --- /dev/null +++ b/ports/stm32/lwip_inc/arch/cc.h @@ -0,0 +1,8 @@ +#ifndef MICROPY_INCLUDED_STM32_LWIP_ARCH_CC_H +#define MICROPY_INCLUDED_STM32_LWIP_ARCH_CC_H + +#include +#define LWIP_PLATFORM_DIAG(x) +#define LWIP_PLATFORM_ASSERT(x) { assert(1); } + +#endif // MICROPY_INCLUDED_STM32_LWIP_ARCH_CC_H diff --git a/ports/stm32/lwip_inc/arch/sys_arch.h b/ports/stm32/lwip_inc/arch/sys_arch.h new file mode 100644 index 0000000000..8b1a393741 --- /dev/null +++ b/ports/stm32/lwip_inc/arch/sys_arch.h @@ -0,0 +1 @@ +// empty diff --git a/ports/stm32/lwip_inc/lwipopts.h b/ports/stm32/lwip_inc/lwipopts.h new file mode 100644 index 0000000000..b8ab8a2ab0 --- /dev/null +++ b/ports/stm32/lwip_inc/lwipopts.h @@ -0,0 +1,61 @@ +#ifndef MICROPY_INCLUDED_STM32_LWIP_LWIPOPTS_H +#define MICROPY_INCLUDED_STM32_LWIP_LWIPOPTS_H + +#include + +#define NO_SYS 1 +#define SYS_LIGHTWEIGHT_PROT 1 +#define MEM_ALIGNMENT 4 + +#define LWIP_CHKSUM_ALGORITHM 3 + +#define LWIP_ARP 1 +#define LWIP_ETHERNET 1 +#define LWIP_NETCONN 0 +#define LWIP_SOCKET 0 +#define LWIP_STATS 0 +#define LWIP_NETIF_HOSTNAME 1 + +#define LWIP_IPV6 0 +#define LWIP_DHCP 1 +#define LWIP_DHCP_CHECK_LINK_UP 1 +#define LWIP_DNS 1 +#define LWIP_IGMP 1 + +#define SO_REUSE 1 + +extern uint32_t rng_get(void); +#define LWIP_RAND() rng_get() + +// default +// lwip takes 15800 bytes; TCP d/l: 380k/s local, 7.2k/s remote +// TCP u/l is very slow + +#if 0 +// lwip takes 19159 bytes; TCP d/l and u/l are around 320k/s on local network +#define MEM_SIZE (5000) +#define TCP_WND (4 * TCP_MSS) +#define TCP_SND_BUF (4 * TCP_MSS) +#endif + +#if 1 +// lwip takes 26700 bytes; TCP dl/ul are around 750/600 k/s on local network +#define MEM_SIZE (8000) +#define TCP_MSS (800) +#define TCP_WND (8 * TCP_MSS) +#define TCP_SND_BUF (8 * TCP_MSS) +#define MEMP_NUM_TCP_SEG (32) +#endif + +#if 0 +// lwip takes 45600 bytes; TCP dl/ul are around 1200/1000 k/s on local network +#define MEM_SIZE (16000) +#define TCP_MSS (1460) +#define TCP_WND (8 * TCP_MSS) +#define TCP_SND_BUF (8 * TCP_MSS) +#define MEMP_NUM_TCP_SEG (32) +#endif + +typedef uint32_t sys_prot_t; + +#endif // MICROPY_INCLUDED_STM32_LWIP_LWIPOPTS_H diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 460a19ccb1..44f5b05c45 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -34,6 +34,7 @@ #include "lib/mp-readline/readline.h" #include "lib/utils/pyexec.h" #include "lib/oofatfs/ff.h" +#include "lwip/init.h" #include "extmod/vfs.h" #include "extmod/vfs_fat.h" @@ -512,6 +513,12 @@ void stm32_main(uint32_t reset_mode) { sdcard_init(); #endif storage_init(); + #if MICROPY_PY_LWIP + // lwIP doesn't allow to reinitialise itself by subsequent calls to this function + // because the system timeout list (next_timeout) is only ever reset by BSS clearing. + // So for now we only init the lwIP stack once on power-up. + lwip_init(); + #endif soft_reset: @@ -726,6 +733,9 @@ soft_reset_exit: storage_flush(); printf("PYB: soft reboot\n"); + #if MICROPY_PY_NETWORK + mod_network_deinit(); + #endif timer_deinit(); uart_deinit(); #if MICROPY_HW_ENABLE_CAN diff --git a/ports/stm32/modnetwork.c b/ports/stm32/modnetwork.c index 6421745325..156c73572e 100644 --- a/ports/stm32/modnetwork.c +++ b/ports/stm32/modnetwork.c @@ -30,10 +30,34 @@ #include "py/objlist.h" #include "py/runtime.h" +#include "py/mphal.h" #include "modnetwork.h" #if MICROPY_PY_NETWORK +#if MICROPY_PY_LWIP + +#include "lwip/netif.h" +#include "lwip/timeouts.h" + +u32_t sys_now(void) { + return mp_hal_ticks_ms(); +} + +void pyb_lwip_poll(void) { + // Poll all the NICs for incoming data + for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) { + if (netif->flags & NETIF_FLAG_LINK_UP) { + mod_network_nic_type_t *nic = netif->state; + nic->poll_callback(nic, netif); + } + } + // Run the lwIP internal updates + sys_check_timeouts(); +} + +#endif + /// \module network - network configuration /// /// This module provides network drivers and routing configuration. @@ -42,6 +66,15 @@ void mod_network_init(void) { mp_obj_list_init(&MP_STATE_PORT(mod_network_nic_list), 0); } +void mod_network_deinit(void) { + #if MICROPY_PY_LWIP + for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) { + netif_remove(netif); + } + // TODO there may be some timeouts that are still pending... + #endif +} + void mod_network_register_nic(mp_obj_t nic) { for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) { if (MP_STATE_PORT(mod_network_nic_list).items[i] == nic) { diff --git a/ports/stm32/modnetwork.h b/ports/stm32/modnetwork.h index 6796b087a4..af46a54a65 100644 --- a/ports/stm32/modnetwork.h +++ b/ports/stm32/modnetwork.h @@ -35,6 +35,17 @@ #define MOD_NETWORK_SOCK_DGRAM (2) #define MOD_NETWORK_SOCK_RAW (3) +#if MICROPY_PY_LWIP + +struct netif; + +typedef struct _mod_network_nic_type_t { + mp_obj_type_t base; + void (*poll_callback)(void *data, struct netif *netif); +} mod_network_nic_type_t; + +#else + struct _mod_network_socket_obj_t; typedef struct _mod_network_nic_type_t { @@ -73,10 +84,13 @@ typedef struct _mod_network_socket_obj_t { }; } mod_network_socket_obj_t; +#endif + extern const mod_network_nic_type_t mod_network_nic_type_wiznet5k; extern const mod_network_nic_type_t mod_network_nic_type_cc3k; void mod_network_init(void); +void mod_network_deinit(void); void mod_network_register_nic(mp_obj_t nic); mp_obj_t mod_network_find_nic(const uint8_t *ip); diff --git a/ports/stm32/modusocket.c b/ports/stm32/modusocket.c index 0c663437e3..715faa3c4b 100644 --- a/ports/stm32/modusocket.c +++ b/ports/stm32/modusocket.c @@ -35,7 +35,7 @@ #include "lib/netutils/netutils.h" #include "modnetwork.h" -#if MICROPY_PY_USOCKET +#if MICROPY_PY_USOCKET && !MICROPY_PY_LWIP /******************************************************************************/ // socket class @@ -465,4 +465,4 @@ const mp_obj_module_t mp_module_usocket = { .globals = (mp_obj_dict_t*)&mp_module_usocket_globals, }; -#endif // MICROPY_PY_USOCKET +#endif // MICROPY_PY_USOCKET && !MICROPY_PY_LWIP diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 72744f04b1..115006367c 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -192,12 +192,21 @@ extern const struct _mp_obj_module_t mp_module_onewire; #define STM_BUILTIN_MODULE #endif -#if MICROPY_PY_USOCKET +#if MICROPY_PY_USOCKET && MICROPY_PY_LWIP +// usocket implementation provided by lwIP +#define SOCKET_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_lwip) }, +#define SOCKET_BUILTIN_MODULE_WEAK_LINKS { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_lwip) }, +#define SOCKET_POLL extern void pyb_lwip_poll(void); pyb_lwip_poll(); +#elif MICROPY_PY_USOCKET +// usocket implementation provided by skeleton wrapper #define SOCKET_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_usocket) }, #define SOCKET_BUILTIN_MODULE_WEAK_LINKS { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_usocket) }, +#define SOCKET_POLL #else +// no usocket module #define SOCKET_BUILTIN_MODULE #define SOCKET_BUILTIN_MODULE_WEAK_LINKS +#define SOCKET_POLL #endif #if MICROPY_PY_NETWORK @@ -313,6 +322,7 @@ static inline mp_uint_t disable_irq(void) { do { \ extern void mp_handle_pending(void); \ mp_handle_pending(); \ + SOCKET_POLL \ if (pyb_thread_enabled) { \ MP_THREAD_GIL_EXIT(); \ pyb_thread_yield(); \ @@ -328,6 +338,7 @@ static inline mp_uint_t disable_irq(void) { do { \ extern void mp_handle_pending(void); \ mp_handle_pending(); \ + SOCKET_POLL \ __WFI(); \ } while (0); From f68e722005c495134065680859c705210d307ccf Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 22 May 2018 10:27:21 +1000 Subject: [PATCH 698/828] stm32/rng: Use Yasmarang for rng_get() if MCU doesn't have HW RNG. --- ports/stm32/rng.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/ports/stm32/rng.c b/ports/stm32/rng.c index e70eafae71..b23941998a 100644 --- a/ports/stm32/rng.c +++ b/ports/stm32/rng.c @@ -60,4 +60,30 @@ STATIC mp_obj_t pyb_rng_get(void) { } MP_DEFINE_CONST_FUN_OBJ_0(pyb_rng_get_obj, pyb_rng_get); +#else // MICROPY_HW_ENABLE_RNG + +// For MCUs that don't have an RNG we still need to provide a rng_get() function, +// eg for lwIP. A pseudo-RNG is not really ideal but we go with it for now. We +// don't want to use urandom's pRNG because then the user won't see a reproducible +// random stream. + +// Yasmarang random number generator by Ilya Levin +// http://www.literatecode.com/yasmarang +STATIC uint32_t pyb_rng_yasmarang(void) { + static uint32_t pad = 0xeda4baba, n = 69, d = 233; + static uint8_t dat = 0; + + pad += dat + d * n; + pad = (pad << 3) + (pad >> 29); + n = pad | 2; + d ^= (pad << 31) + (pad >> 1); + dat ^= (char)pad ^ (d >> 8) ^ 1; + + return pad ^ (d << 5) ^ (pad >> 18) ^ (dat << 1); +} + +uint32_t rng_get(void) { + return pyb_rng_yasmarang(); +} + #endif // MICROPY_HW_ENABLE_RNG From e773a2cdba11703a0286044b26dfb3da1ae73928 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 22 May 2018 13:17:03 +1000 Subject: [PATCH 699/828] stm32/main: Use consistent indenting of macro #if's. --- ports/stm32/main.c | 60 ++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 44f5b05c45..5c75355422 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -343,12 +343,12 @@ STATIC bool init_sdcard_fs(void) { #if !MICROPY_HW_USES_BOOTLOADER STATIC uint update_reset_mode(uint reset_mode) { -#if MICROPY_HW_HAS_SWITCH + #if MICROPY_HW_HAS_SWITCH if (switch_get()) { // The original method used on the pyboard is appropriate if you have 2 // or more LEDs. -#if defined(MICROPY_HW_LED2) + #if defined(MICROPY_HW_LED2) for (uint i = 0; i < 3000; i++) { if (!switch_get()) { break; @@ -376,7 +376,7 @@ STATIC uint update_reset_mode(uint reset_mode) { } mp_hal_delay_ms(400); -#elif defined(MICROPY_HW_LED1) + #elif defined(MICROPY_HW_LED1) // For boards with only a single LED, we'll flash that LED the // appropriate number of times, with a pause between each one @@ -409,11 +409,11 @@ STATIC uint update_reset_mode(uint reset_mode) { } mp_hal_delay_ms(400); } -#else -#error Need a reset mode update method -#endif + #else + #error Need a reset mode update method + #endif } -#endif + #endif return reset_mode; } #endif @@ -522,13 +522,13 @@ void stm32_main(uint32_t reset_mode) { soft_reset: -#if defined(MICROPY_HW_LED2) + #if defined(MICROPY_HW_LED2) led_state(1, 0); led_state(2, 1); -#else + #else led_state(1, 1); led_state(2, 0); -#endif + #endif led_state(3, 0); led_state(4, 0); @@ -576,7 +576,7 @@ soft_reset: // Define MICROPY_HW_UART_REPL to be PYB_UART_6 and define // MICROPY_HW_UART_REPL_BAUD in your mpconfigboard.h file if you want a // REPL on a hardware UART as well as on USB VCP -#if defined(MICROPY_HW_UART_REPL) + #if defined(MICROPY_HW_UART_REPL) { mp_obj_t args[2] = { MP_OBJ_NEW_SMALL_INT(MICROPY_HW_UART_REPL), @@ -585,13 +585,13 @@ soft_reset: MP_STATE_PORT(pyb_stdio_uart) = pyb_uart_type.make_new((mp_obj_t)&pyb_uart_type, MP_ARRAY_SIZE(args), 0, args); uart_attach_to_repl(MP_STATE_PORT(pyb_stdio_uart), true); } -#else + #else MP_STATE_PORT(pyb_stdio_uart) = NULL; -#endif + #endif -#if MICROPY_HW_ENABLE_CAN + #if MICROPY_HW_ENABLE_CAN can_init0(); -#endif + #endif #if MICROPY_HW_ENABLE_USB pyb_usb_init0(); @@ -602,7 +602,7 @@ soft_reset: bool mounted_flash = init_flash_fs(reset_mode); bool mounted_sdcard = false; -#if MICROPY_HW_HAS_SDCARD + #if MICROPY_HW_HAS_SDCARD // if an SD card is present then mount it on /sd/ if (sdcard_is_present()) { // if there is a file in the flash called "SKIPSD", then we don't mount the SD card @@ -610,7 +610,7 @@ soft_reset: mounted_sdcard = init_sdcard_fs(); } } -#endif + #endif #if MICROPY_HW_ENABLE_USB // if the SD card isn't used as the USB MSC medium then use the internal flash @@ -649,12 +649,12 @@ soft_reset: } // turn boot-up LEDs off -#if !defined(MICROPY_HW_LED2) + #if !defined(MICROPY_HW_LED2) // If there is only one LED on the board then it's used to signal boot-up // and so we turn it off here. Otherwise LED(1) is used to indicate dirty // flash cache and so we shouldn't change its state. led_state(1, 0); -#endif + #endif led_state(2, 0); led_state(3, 0); led_state(4, 0); @@ -670,24 +670,22 @@ soft_reset: } #endif -#if MICROPY_HW_HAS_MMA7660 + #if MICROPY_HW_HAS_MMA7660 // MMA accel: init and reset accel_init(); -#endif + #endif -#if MICROPY_HW_ENABLE_SERVO - // servo + #if MICROPY_HW_ENABLE_SERVO servo_init(); -#endif + #endif -#if MICROPY_HW_ENABLE_DAC - // DAC + #if MICROPY_HW_ENABLE_DAC dac_init(); -#endif + #endif -#if MICROPY_PY_NETWORK + #if MICROPY_PY_NETWORK mod_network_init(); -#endif + #endif // At this point everything is fully configured and initialised. @@ -738,9 +736,9 @@ soft_reset_exit: #endif timer_deinit(); uart_deinit(); -#if MICROPY_HW_ENABLE_CAN + #if MICROPY_HW_ENABLE_CAN can_deinit(); -#endif + #endif machine_deinit(); #if MICROPY_PY_THREAD From f2ec7925542e5a75b2da7ef378f5df66fdb6fad9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 22 May 2018 13:20:00 +1000 Subject: [PATCH 700/828] py/parsenum: Adjust braces so they are balanced. --- py/parsenum.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/py/parsenum.c b/py/parsenum.c index ba7e40afd6..354d0f756c 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -319,11 +319,13 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool return mp_obj_new_complex(0, dec_val); } else if (force_complex) { return mp_obj_new_complex(dec_val, 0); + } #else if (imag || force_complex) { raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, "complex values not supported"), lex); + } #endif - } else { + else { return mp_obj_new_float(dec_val); } From b318ebf1015ced6354f8bbaf035308214b3f5c5d Mon Sep 17 00:00:00 2001 From: Jan Klusacek Date: Tue, 9 Jan 2018 22:47:35 +0100 Subject: [PATCH 701/828] py/modbuiltins: Add support for rounding integers. As per CPython semantics. This feature is controlled by MICROPY_PY_BUILTINS_ROUND_INT which is disabled by default. --- py/modbuiltins.c | 31 +++++++++++++++++++++++++++- py/mpconfig.h | 5 +++++ tests/basics/builtin_round_int.py | 18 ++++++++++++++++ tests/basics/builtin_round_intbig.py | 17 +++++++++++++++ 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 tests/basics/builtin_round_int.py create mode 100644 tests/basics/builtin_round_intbig.py diff --git a/py/modbuiltins.c b/py/modbuiltins.c index 0d511338b0..b216e021f3 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -445,7 +445,36 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_repr_obj, mp_builtin_repr); STATIC mp_obj_t mp_builtin_round(size_t n_args, const mp_obj_t *args) { mp_obj_t o_in = args[0]; if (MP_OBJ_IS_INT(o_in)) { - return o_in; + if (n_args <= 1) { + return o_in; + } + + #if !MICROPY_PY_BUILTINS_ROUND_INT + mp_raise_NotImplementedError(NULL); + #else + mp_int_t num_dig = mp_obj_get_int(args[1]); + if (num_dig >= 0) { + return o_in; + } + + mp_obj_t mult = mp_binary_op(MP_BINARY_OP_POWER, MP_OBJ_NEW_SMALL_INT(10), MP_OBJ_NEW_SMALL_INT(-num_dig)); + mp_obj_t half_mult = mp_binary_op(MP_BINARY_OP_FLOOR_DIVIDE, mult, MP_OBJ_NEW_SMALL_INT(2)); + mp_obj_t modulo = mp_binary_op(MP_BINARY_OP_MODULO, o_in, mult); + mp_obj_t rounded = mp_binary_op(MP_BINARY_OP_SUBTRACT, o_in, modulo); + if (mp_obj_is_true(mp_binary_op(MP_BINARY_OP_MORE, half_mult, modulo))) { + return rounded; + } else if (mp_obj_is_true(mp_binary_op(MP_BINARY_OP_MORE, modulo, half_mult))) { + return mp_binary_op(MP_BINARY_OP_ADD, rounded, mult); + } else { + // round to even number + mp_obj_t floor = mp_binary_op(MP_BINARY_OP_FLOOR_DIVIDE, o_in, mult); + if (mp_obj_is_true(mp_binary_op(MP_BINARY_OP_AND, floor, MP_OBJ_NEW_SMALL_INT(1)))) { + return mp_binary_op(MP_BINARY_OP_ADD, rounded, mult); + } else { + return rounded; + } + } + #endif } #if MICROPY_PY_BUILTINS_FLOAT mp_float_t val = mp_obj_get_float(o_in); diff --git a/py/mpconfig.h b/py/mpconfig.h index c42fe78536..100e2a9810 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -802,6 +802,11 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_RANGE_BINOP (0) #endif +// Whether to support rounding of integers (incl bignum); eg round(123,-1)=120 +#ifndef MICROPY_PY_BUILTINS_ROUND_INT +#define MICROPY_PY_BUILTINS_ROUND_INT (0) +#endif + // Whether to support timeout exceptions (like socket.timeout) #ifndef MICROPY_PY_BUILTINS_TIMEOUTERROR #define MICROPY_PY_BUILTINS_TIMEOUTERROR (0) diff --git a/tests/basics/builtin_round_int.py b/tests/basics/builtin_round_int.py new file mode 100644 index 0000000000..a2017622a7 --- /dev/null +++ b/tests/basics/builtin_round_int.py @@ -0,0 +1,18 @@ +# test round() with integer values and second arg + +# rounding integers is an optional feature so test for it +try: + round(1, -1) +except NotImplementedError: + print('SKIP') + raise SystemExit + +tests = [ + (1, False), (1, True), + (124, -1), (125, -1), (126, -1), + (5, -1), (15, -1), (25, -1), + (12345, 0), (12345, -1), (12345, 1), + (-1234, 0), (-1234, -1), (-1234, 1), +] +for t in tests: + print(round(*t)) diff --git a/tests/basics/builtin_round_intbig.py b/tests/basics/builtin_round_intbig.py new file mode 100644 index 0000000000..adf9d29f2f --- /dev/null +++ b/tests/basics/builtin_round_intbig.py @@ -0,0 +1,17 @@ +# test round() with large integer values and second arg + +# rounding integers is an optional feature so test for it +try: + round(1, -1) +except NotImplementedError: + print('SKIP') + raise SystemExit + +i = 2**70 + +tests = [ + (i, 0), (i, -1), (i, -10), (i, 1), + (-i, 0), (-i, -1), (-i, -10), (-i, 1), +] +for t in tests: + print(round(*t)) From 20b4b85f7266ef2edbe492829585a14118a85d7a Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 22 May 2018 14:15:20 +1000 Subject: [PATCH 702/828] ports: Enable MICROPY_PY_BUILTINS_ROUND_INT on selected ports. --- ports/esp32/mpconfigport.h | 1 + ports/esp8266/mpconfigport.h | 1 + ports/stm32/mpconfigport.h | 1 + ports/unix/mpconfigport.h | 1 + 4 files changed, 4 insertions(+) diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index b36bd2ebc9..c7a87e3afe 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -70,6 +70,7 @@ #define MICROPY_PY_BUILTINS_FROZENSET (1) #define MICROPY_PY_BUILTINS_PROPERTY (1) #define MICROPY_PY_BUILTINS_RANGE_ATTRS (1) +#define MICROPY_PY_BUILTINS_ROUND_INT (1) #define MICROPY_PY_BUILTINS_TIMEOUTERROR (1) #define MICROPY_PY_ALL_SPECIAL_METHODS (1) #define MICROPY_PY_BUILTINS_COMPILE (1) diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index ec347dae08..f29dbe5c02 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -40,6 +40,7 @@ #define MICROPY_PY_BUILTINS_SLICE (1) #define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) #define MICROPY_PY_BUILTINS_PROPERTY (1) +#define MICROPY_PY_BUILTINS_ROUND_INT (1) #define MICROPY_PY_BUILTINS_INPUT (1) #define MICROPY_PY_BUILTINS_HELP (1) #define MICROPY_PY_BUILTINS_HELP_TEXT esp_help_text diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 115006367c..84e4892976 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -87,6 +87,7 @@ #define MICROPY_PY_BUILTINS_MEMORYVIEW (1) #define MICROPY_PY_BUILTINS_FROZENSET (1) #define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) +#define MICROPY_PY_BUILTINS_ROUND_INT (1) #define MICROPY_PY_ALL_SPECIAL_METHODS (1) #define MICROPY_PY_BUILTINS_COMPILE (1) #define MICROPY_PY_BUILTINS_EXECFILE (1) diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index 06dae9da83..f0e17ccad0 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -83,6 +83,7 @@ #define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1) #define MICROPY_PY_BUILTINS_INPUT (1) #define MICROPY_PY_BUILTINS_POW3 (1) +#define MICROPY_PY_BUILTINS_ROUND_INT (1) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) #define MICROPY_PY_ALL_SPECIAL_METHODS (1) #define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) From 771cb359af5242762baa29645c37cafa23c47b25 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 22 May 2018 16:39:19 +1000 Subject: [PATCH 703/828] py/objgenerator: Save state in old_globals instead of local variable. The code_state.old_globals variable is there to save the globals state so should be used for this purpose, to avoid the need for additional local variables on the C stack. --- py/objgenerator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/py/objgenerator.c b/py/objgenerator.c index 5fd13f831d..d500dbd9d9 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -117,10 +117,10 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ *self->code_state.sp = send_value; } } - mp_obj_dict_t *old_globals = mp_globals_get(); + self->code_state.old_globals = mp_globals_get(); mp_globals_set(self->globals); mp_vm_return_kind_t ret_kind = mp_execute_bytecode(&self->code_state, throw_value); - mp_globals_set(old_globals); + mp_globals_set(self->code_state.old_globals); switch (ret_kind) { case MP_VM_RETURN_NORMAL: From 400273a799581e5eb86538d8c88fb872705475ab Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 22 May 2018 16:54:03 +1000 Subject: [PATCH 704/828] py/objgenerator: Protect against reentering a generator. Generators that are already executing cannot be reexecuted. This patch puts in a check for such a case. Thanks to @jepler for finding the bug. --- py/objgenerator.c | 10 ++++++++++ tests/basics/gen_yield_from_executing.py | 15 +++++++++++++++ tests/run-tests | 2 +- 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tests/basics/gen_yield_from_executing.py diff --git a/py/objgenerator.c b/py/objgenerator.c index d500dbd9d9..a2ad490d63 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -117,9 +117,19 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ *self->code_state.sp = send_value; } } + + // We set self->globals=NULL while executing, for a sentinel to ensure the generator + // cannot be reentered during execution + if (self->globals == NULL) { + mp_raise_ValueError("generator already executing"); + } + + // Set up the correct globals context for the generator and execute it self->code_state.old_globals = mp_globals_get(); mp_globals_set(self->globals); + self->globals = NULL; mp_vm_return_kind_t ret_kind = mp_execute_bytecode(&self->code_state, throw_value); + self->globals = mp_globals_get(); mp_globals_set(self->code_state.old_globals); switch (ret_kind) { diff --git a/tests/basics/gen_yield_from_executing.py b/tests/basics/gen_yield_from_executing.py new file mode 100644 index 0000000000..cad0c76957 --- /dev/null +++ b/tests/basics/gen_yield_from_executing.py @@ -0,0 +1,15 @@ +# yielding from an already executing generator is not allowed + +def f(): + yield 1 + # g here is already executing so this will raise an exception + yield from g + +g = f() + +print(next(g)) + +try: + next(g) +except ValueError: + print('ValueError') diff --git a/tests/run-tests b/tests/run-tests index afefa264fd..25fb33a3fd 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -336,7 +336,7 @@ def run_tests(pyb, tests, args, base_path="."): # Some tests are known to fail with native emitter # Remove them from the below when they work if args.emit == 'native': - skip_tests.update({'basics/%s.py' % t for t in 'gen_yield_from gen_yield_from_close gen_yield_from_ducktype gen_yield_from_exc gen_yield_from_iter gen_yield_from_send gen_yield_from_stopped gen_yield_from_throw gen_yield_from_throw2 gen_yield_from_throw3 generator1 generator2 generator_args generator_close generator_closure generator_exc generator_pend_throw generator_return generator_send'.split()}) # require yield + skip_tests.update({'basics/%s.py' % t for t in 'gen_yield_from gen_yield_from_close gen_yield_from_ducktype gen_yield_from_exc gen_yield_from_executing gen_yield_from_iter gen_yield_from_send gen_yield_from_stopped gen_yield_from_throw gen_yield_from_throw2 gen_yield_from_throw3 generator1 generator2 generator_args generator_close generator_closure generator_exc generator_pend_throw generator_return generator_send'.split()}) # require yield skip_tests.update({'basics/%s.py' % t for t in 'bytes_gen class_store_class globals_del string_join'.split()}) # require yield skip_tests.update({'basics/async_%s.py' % t for t in 'def await await2 for for2 with with2'.split()}) # require yield skip_tests.update({'basics/%s.py' % t for t in 'try_reraise try_reraise2'.split()}) # require raise_varargs From 0a25fff9562e3051d85db9ca773f203620004742 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 19 May 2018 00:11:04 +1000 Subject: [PATCH 705/828] py/emit: Combine fast and deref into one function for load/store/delete. Reduces code size by: bare-arm: -16 minimal x86: -208 unix x64: -408 unix nanbox: -248 stm32: -12 cc3200: -24 esp8266: -96 esp32: -44 --- py/compile.c | 4 ++-- py/emit.h | 16 +++++++------- py/emitbc.c | 57 +++++++++++++++++-------------------------------- py/emitcommon.c | 4 ++-- py/emitnative.c | 48 ++++++++++++++++++++++++----------------- 5 files changed, 61 insertions(+), 68 deletions(-) diff --git a/py/compile.c b/py/compile.c index c2dd914f03..4d985a07fc 100644 --- a/py/compile.c +++ b/py/compile.c @@ -65,7 +65,7 @@ typedef enum { // we need a method table to do the lookup for the emitter functions #define EMIT(fun) (comp->emit_method_table->fun(comp->emit)) #define EMIT_ARG(fun, ...) (comp->emit_method_table->fun(comp->emit, __VA_ARGS__)) -#define EMIT_LOAD_FAST(qst, local_num) (comp->emit_method_table->load_id.fast(comp->emit, qst, local_num)) +#define EMIT_LOAD_FAST(qst, local_num) (comp->emit_method_table->load_id.local(comp->emit, qst, local_num, MP_EMIT_IDOP_LOCAL_FAST)) #define EMIT_LOAD_GLOBAL(qst) (comp->emit_method_table->load_id.global(comp->emit, qst)) #else @@ -73,7 +73,7 @@ typedef enum { // if we only have the bytecode emitter enabled then we can do a direct call to the functions #define EMIT(fun) (mp_emit_bc_##fun(comp->emit)) #define EMIT_ARG(fun, ...) (mp_emit_bc_##fun(comp->emit, __VA_ARGS__)) -#define EMIT_LOAD_FAST(qst, local_num) (mp_emit_bc_load_fast(comp->emit, qst, local_num)) +#define EMIT_LOAD_FAST(qst, local_num) (mp_emit_bc_load_local(comp->emit, qst, local_num, MP_EMIT_IDOP_LOCAL_FAST)) #define EMIT_LOAD_GLOBAL(qst) (mp_emit_bc_load_global(comp->emit, qst)) #endif diff --git a/py/emit.h b/py/emit.h index 270a40633c..5fe3c3d1f6 100644 --- a/py/emit.h +++ b/py/emit.h @@ -55,11 +55,14 @@ typedef enum { #define MP_EMIT_NATIVE_TYPE_RETURN (1) #define MP_EMIT_NATIVE_TYPE_ARG (2) +// Kind for emit_id_ops->local() +#define MP_EMIT_IDOP_LOCAL_FAST (0) +#define MP_EMIT_IDOP_LOCAL_DEREF (1) + typedef struct _emit_t emit_t; typedef struct _mp_emit_method_table_id_ops_t { - void (*fast)(emit_t *emit, qstr qst, mp_uint_t local_num); - void (*deref)(emit_t *emit, qstr qst, mp_uint_t local_num); + void (*local)(emit_t *emit, qstr qst, mp_uint_t local_num, int kind); void (*name)(emit_t *emit, qstr qst); void (*global)(emit_t *emit, qstr qst); } mp_emit_method_table_id_ops_t; @@ -180,16 +183,13 @@ bool mp_emit_bc_last_emit_was_return_value(emit_t *emit); void mp_emit_bc_adjust_stack_size(emit_t *emit, mp_int_t delta); void mp_emit_bc_set_source_line(emit_t *emit, mp_uint_t line); -void mp_emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num); -void mp_emit_bc_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num); +void mp_emit_bc_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind); void mp_emit_bc_load_name(emit_t *emit, qstr qst); void mp_emit_bc_load_global(emit_t *emit, qstr qst); -void mp_emit_bc_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num); -void mp_emit_bc_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num); +void mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind); void mp_emit_bc_store_name(emit_t *emit, qstr qst); void mp_emit_bc_store_global(emit_t *emit, qstr qst); -void mp_emit_bc_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num); -void mp_emit_bc_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num); +void mp_emit_bc_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind); void mp_emit_bc_delete_name(emit_t *emit, qstr qst); void mp_emit_bc_delete_global(emit_t *emit, qstr qst); diff --git a/py/emitbc.c b/py/emitbc.c index b1b61ba67e..28d32d4ea8 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -556,22 +556,18 @@ void mp_emit_bc_load_null(emit_t *emit) { emit_write_bytecode_byte(emit, MP_BC_LOAD_NULL); } -void mp_emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { +void mp_emit_bc_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { + MP_STATIC_ASSERT(MP_BC_LOAD_FAST_N + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_LOAD_FAST_N); + MP_STATIC_ASSERT(MP_BC_LOAD_FAST_N + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_LOAD_DEREF); (void)qst; emit_bc_pre(emit, 1); - if (local_num <= 15) { + if (kind == MP_EMIT_IDOP_LOCAL_FAST && local_num <= 15) { emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_MULTI + local_num); } else { - emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_FAST_N, local_num); + emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_FAST_N + kind, local_num); } } -void mp_emit_bc_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) { - (void)qst; - emit_bc_pre(emit, 1); - emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_DEREF, local_num); -} - void mp_emit_bc_load_name(emit_t *emit, qstr qst) { (void)qst; emit_bc_pre(emit, 1); @@ -613,22 +609,18 @@ void mp_emit_bc_load_subscr(emit_t *emit) { emit_write_bytecode_byte(emit, MP_BC_LOAD_SUBSCR); } -void mp_emit_bc_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { +void mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { + MP_STATIC_ASSERT(MP_BC_STORE_FAST_N + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_STORE_FAST_N); + MP_STATIC_ASSERT(MP_BC_STORE_FAST_N + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_STORE_DEREF); (void)qst; emit_bc_pre(emit, -1); - if (local_num <= 15) { + if (kind == MP_EMIT_IDOP_LOCAL_FAST && local_num <= 15) { emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_MULTI + local_num); } else { - emit_write_bytecode_byte_uint(emit, MP_BC_STORE_FAST_N, local_num); + emit_write_bytecode_byte_uint(emit, MP_BC_STORE_FAST_N + kind, local_num); } } -void mp_emit_bc_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num) { - (void)qst; - emit_bc_pre(emit, -1); - emit_write_bytecode_byte_uint(emit, MP_BC_STORE_DEREF, local_num); -} - void mp_emit_bc_store_name(emit_t *emit, qstr qst) { emit_bc_pre(emit, -1); emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_NAME, qst); @@ -652,14 +644,11 @@ void mp_emit_bc_store_subscr(emit_t *emit) { emit_write_bytecode_byte(emit, MP_BC_STORE_SUBSCR); } -void mp_emit_bc_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { +void mp_emit_bc_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { + MP_STATIC_ASSERT(MP_BC_DELETE_FAST + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_DELETE_FAST); + MP_STATIC_ASSERT(MP_BC_DELETE_FAST + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_DELETE_DEREF); (void)qst; - emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_FAST, local_num); -} - -void mp_emit_bc_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num) { - (void)qst; - emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_DEREF, local_num); + emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_FAST + kind, local_num); } void mp_emit_bc_delete_name(emit_t *emit, qstr qst) { @@ -972,20 +961,17 @@ const emit_method_table_t emit_bc_method_table = { mp_emit_bc_set_source_line, { - mp_emit_bc_load_fast, - mp_emit_bc_load_deref, + mp_emit_bc_load_local, mp_emit_bc_load_name, mp_emit_bc_load_global, }, { - mp_emit_bc_store_fast, - mp_emit_bc_store_deref, + mp_emit_bc_store_local, mp_emit_bc_store_name, mp_emit_bc_store_global, }, { - mp_emit_bc_delete_fast, - mp_emit_bc_delete_deref, + mp_emit_bc_delete_local, mp_emit_bc_delete_name, mp_emit_bc_delete_global, }, @@ -1056,22 +1042,19 @@ const emit_method_table_t emit_bc_method_table = { }; #else const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_load_id_ops = { - mp_emit_bc_load_fast, - mp_emit_bc_load_deref, + mp_emit_bc_load_local, mp_emit_bc_load_name, mp_emit_bc_load_global, }; const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_store_id_ops = { - mp_emit_bc_store_fast, - mp_emit_bc_store_deref, + mp_emit_bc_store_local, mp_emit_bc_store_name, mp_emit_bc_store_global, }; const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_delete_id_ops = { - mp_emit_bc_delete_fast, - mp_emit_bc_delete_deref, + mp_emit_bc_delete_local, mp_emit_bc_delete_name, mp_emit_bc_delete_global, }; diff --git a/py/emitcommon.c b/py/emitcommon.c index 07b1dbb4ce..47fd41ef2e 100644 --- a/py/emitcommon.c +++ b/py/emitcommon.c @@ -67,10 +67,10 @@ void mp_emit_common_id_op(emit_t *emit, const mp_emit_method_table_id_ops_t *emi } else if (id->kind == ID_INFO_KIND_GLOBAL_EXPLICIT) { emit_method_table->global(emit, qst); } else if (id->kind == ID_INFO_KIND_LOCAL) { - emit_method_table->fast(emit, qst, id->local_num); + emit_method_table->local(emit, qst, id->local_num, MP_EMIT_IDOP_LOCAL_FAST); } else { assert(id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE); - emit_method_table->deref(emit, qst, id->local_num); + emit_method_table->local(emit, qst, id->local_num, MP_EMIT_IDOP_LOCAL_DEREF); } } diff --git a/py/emitnative.c b/py/emitnative.c index 7e017ba39f..9e16ef4bd9 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -938,6 +938,14 @@ STATIC void emit_native_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } +STATIC void emit_native_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { + if (kind == MP_EMIT_IDOP_LOCAL_FAST) { + emit_native_load_fast(emit, qst, local_num); + } else { + emit_native_load_deref(emit, qst, local_num); + } +} + STATIC void emit_native_load_name(emit_t *emit, qstr qst) { DEBUG_printf("load_name(%s)\n", qstr_str(qst)); emit_native_pre(emit); @@ -1178,6 +1186,14 @@ STATIC void emit_native_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num) emit_post(emit); } +STATIC void emit_native_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { + if (kind == MP_EMIT_IDOP_LOCAL_FAST) { + emit_native_store_fast(emit, qst, local_num); + } else { + emit_native_store_deref(emit, qst, local_num); + } +} + STATIC void emit_native_store_name(emit_t *emit, qstr qst) { // mp_store_name, but needs conversion of object (maybe have mp_viper_store_name(obj, type)) vtype_kind_t vtype; @@ -1389,19 +1405,16 @@ STATIC void emit_native_store_subscr(emit_t *emit) { } } -STATIC void emit_native_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { - // TODO: This is not compliant implementation. We could use MP_OBJ_SENTINEL - // to mark deleted vars but then every var would need to be checked on - // each access. Very inefficient, so just set value to None to enable GC. - emit_native_load_const_tok(emit, MP_TOKEN_KW_NONE); - emit_native_store_fast(emit, qst, local_num); -} - -STATIC void emit_native_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num) { - // TODO implement me! - (void)emit; - (void)qst; - (void)local_num; +STATIC void emit_native_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { + if (kind == MP_EMIT_IDOP_LOCAL_FAST) { + // TODO: This is not compliant implementation. We could use MP_OBJ_SENTINEL + // to mark deleted vars but then every var would need to be checked on + // each access. Very inefficient, so just set value to None to enable GC. + emit_native_load_const_tok(emit, MP_TOKEN_KW_NONE); + emit_native_store_fast(emit, qst, local_num); + } else { + // TODO implement me! + } } STATIC void emit_native_delete_name(emit_t *emit, qstr qst) { @@ -2192,20 +2205,17 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_set_source_line, { - emit_native_load_fast, - emit_native_load_deref, + emit_native_load_local, emit_native_load_name, emit_native_load_global, }, { - emit_native_store_fast, - emit_native_store_deref, + emit_native_store_local, emit_native_store_name, emit_native_store_global, }, { - emit_native_delete_fast, - emit_native_delete_deref, + emit_native_delete_local, emit_native_delete_name, emit_native_delete_global, }, From e686c940525c5b87d02e3dd7bfcdec23cfa996dd Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 19 May 2018 00:30:42 +1000 Subject: [PATCH 706/828] py/emit: Combine yield value and yield-from emit funcs into one. Reduces code size by: bare-arm: -24 minimal x86: -72 unix x64: -200 unix nanbox: -72 stm32: -52 cc3200: -32 esp8266: -84 esp32: -24 --- py/compile.c | 8 ++++---- py/emit.h | 10 ++++++---- py/emitbc.c | 16 +++++----------- py/emitnative.c | 11 +++-------- tests/micropython/viper_error.py.exp | 2 +- 5 files changed, 19 insertions(+), 28 deletions(-) diff --git a/py/compile.c b/py/compile.c index 4d985a07fc..743034e57c 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1699,7 +1699,7 @@ STATIC void compile_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { STATIC void compile_yield_from(compiler_t *comp) { EMIT_ARG(get_iter, false); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); - EMIT(yield_from); + EMIT_ARG(yield, MP_EMIT_YIELD_FROM); } #if MICROPY_PY_ASYNC_AWAIT @@ -2621,14 +2621,14 @@ STATIC void compile_yield_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { } if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); - EMIT(yield_value); + EMIT_ARG(yield, MP_EMIT_YIELD_VALUE); } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_yield_arg_from)) { pns = (mp_parse_node_struct_t*)pns->nodes[0]; compile_node(comp, pns->nodes[0]); compile_yield_from(comp); } else { compile_node(comp, pns->nodes[0]); - EMIT(yield_value); + EMIT_ARG(yield, MP_EMIT_YIELD_VALUE); } } @@ -2862,7 +2862,7 @@ STATIC void compile_scope_comp_iter(compiler_t *comp, mp_parse_node_struct_t *pn // no more nested if/for; compile inner expression compile_node(comp, pn_inner_expr); if (comp->scope_cur->kind == SCOPE_GEN_EXPR) { - EMIT(yield_value); + EMIT_ARG(yield, MP_EMIT_YIELD_VALUE); EMIT(pop_top); } else { EMIT_ARG(store_comp, comp->scope_cur->kind, 4 * for_depth + 5); diff --git a/py/emit.h b/py/emit.h index 5fe3c3d1f6..c85df0a675 100644 --- a/py/emit.h +++ b/py/emit.h @@ -59,6 +59,10 @@ typedef enum { #define MP_EMIT_IDOP_LOCAL_FAST (0) #define MP_EMIT_IDOP_LOCAL_DEREF (1) +// Kind for emit->yield() +#define MP_EMIT_YIELD_VALUE (0) +#define MP_EMIT_YIELD_FROM (1) + typedef struct _emit_t emit_t; typedef struct _mp_emit_method_table_id_ops_t { @@ -137,8 +141,7 @@ typedef struct _emit_method_table_t { void (*call_method)(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags); void (*return_value)(emit_t *emit); void (*raise_varargs)(emit_t *emit, mp_uint_t n_args); - void (*yield_value)(emit_t *emit); - void (*yield_from)(emit_t *emit); + void (*yield)(emit_t *emit, int kind); // these methods are used to control entry to/exit from an exception handler // they may or may not emit code @@ -252,8 +255,7 @@ void mp_emit_bc_call_function(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_ void mp_emit_bc_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags); void mp_emit_bc_return_value(emit_t *emit); void mp_emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args); -void mp_emit_bc_yield_value(emit_t *emit); -void mp_emit_bc_yield_from(emit_t *emit); +void mp_emit_bc_yield(emit_t *emit, int kind); void mp_emit_bc_start_except_handler(emit_t *emit); void mp_emit_bc_end_except_handler(emit_t *emit); diff --git a/py/emitbc.c b/py/emitbc.c index 28d32d4ea8..bff2c5a4c5 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -931,16 +931,11 @@ void mp_emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args) { emit_write_bytecode_byte_byte(emit, MP_BC_RAISE_VARARGS, n_args); } -void mp_emit_bc_yield_value(emit_t *emit) { - emit_bc_pre(emit, 0); +void mp_emit_bc_yield(emit_t *emit, int kind) { + MP_STATIC_ASSERT(MP_BC_YIELD_VALUE + 1 == MP_BC_YIELD_FROM); + emit_bc_pre(emit, -kind); emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; - emit_write_bytecode_byte(emit, MP_BC_YIELD_VALUE); -} - -void mp_emit_bc_yield_from(emit_t *emit) { - emit_bc_pre(emit, -1); - emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; - emit_write_bytecode_byte(emit, MP_BC_YIELD_FROM); + emit_write_bytecode_byte(emit, MP_BC_YIELD_VALUE + kind); } void mp_emit_bc_start_except_handler(emit_t *emit) { @@ -1034,8 +1029,7 @@ const emit_method_table_t emit_bc_method_table = { mp_emit_bc_call_method, mp_emit_bc_return_value, mp_emit_bc_raise_varargs, - mp_emit_bc_yield_value, - mp_emit_bc_yield_from, + mp_emit_bc_yield, mp_emit_bc_start_except_handler, mp_emit_bc_end_except_handler, diff --git a/py/emitnative.c b/py/emitnative.c index 9e16ef4bd9..26bcebfcbb 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -2170,16 +2170,12 @@ STATIC void emit_native_raise_varargs(emit_t *emit, mp_uint_t n_args) { emit_call(emit, MP_F_NATIVE_RAISE); } -STATIC void emit_native_yield_value(emit_t *emit) { +STATIC void emit_native_yield(emit_t *emit, int kind) { // not supported (for now) (void)emit; + (void)kind; mp_raise_NotImplementedError("native yield"); } -STATIC void emit_native_yield_from(emit_t *emit) { - // not supported (for now) - (void)emit; - mp_raise_NotImplementedError("native yield from"); -} STATIC void emit_native_start_except_handler(emit_t *emit) { // This instruction follows an nlr_pop, so the stack counter is back to zero, when really @@ -2278,8 +2274,7 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_call_method, emit_native_return_value, emit_native_raise_varargs, - emit_native_yield_value, - emit_native_yield_from, + emit_native_yield, emit_native_start_except_handler, emit_native_end_except_handler, diff --git a/tests/micropython/viper_error.py.exp b/tests/micropython/viper_error.py.exp index a44fb3ff0a..3a8cb02994 100644 --- a/tests/micropython/viper_error.py.exp +++ b/tests/micropython/viper_error.py.exp @@ -20,6 +20,6 @@ ViperTypeError('unary op __neg__ not implemented',) ViperTypeError('unary op __invert__ not implemented',) ViperTypeError('binary op not implemented',) NotImplementedError('native yield',) -NotImplementedError('native yield from',) +NotImplementedError('native yield',) NotImplementedError('conversion to object',) NotImplementedError('casting',) From 26b5754092134b53e03eed8c5e6c580d28a2a829 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 19 May 2018 00:41:40 +1000 Subject: [PATCH 707/828] py/emit: Combine build tuple/list/map emit funcs into one. Reduces code size by: bare-arm: -24 minimal x86: -192 unix x64: -288 unix nanbox: -184 stm32: -72 cc3200: -16 esp8266: -148 esp32: -32 --- py/compile.c | 32 ++++++++++++++++---------------- py/emit.h | 13 +++++++------ py/emitbc.c | 27 +++++++++++---------------- py/emitnative.c | 30 ++++++++++-------------------- 4 files changed, 44 insertions(+), 58 deletions(-) diff --git a/py/compile.c b/py/compile.c index 743034e57c..6f0be8fa8c 100644 --- a/py/compile.c +++ b/py/compile.c @@ -273,7 +273,7 @@ STATIC void c_tuple(compiler_t *comp, mp_parse_node_t pn, mp_parse_node_struct_t } total += n; } - EMIT_ARG(build_tuple, total); + EMIT_ARG(build, total, MP_EMIT_BUILD_TUPLE); } STATIC void compile_generic_tuple(compiler_t *comp, mp_parse_node_struct_t *pns) { @@ -652,12 +652,12 @@ STATIC void compile_funcdef_lambdef_param(compiler_t *comp, mp_parse_node_t pn) // in MicroPython we put the default positional parameters into a tuple using the bytecode // 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); + EMIT_ARG(build, comp->num_default_params, MP_EMIT_BUILD_TUPLE); } else { EMIT(load_null); // sentinel indicating empty default positional args } // first default dict param, so make the map - EMIT_ARG(build_map, 0); + EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP); } // compile value then key, then store it to the dict @@ -693,7 +693,7 @@ STATIC void compile_funcdef_lambdef(compiler_t *comp, scope_t *scope, mp_parse_n // in MicroPython we put the default positional parameters into a tuple using the bytecode // 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_ARG(build, comp->num_default_params, MP_EMIT_BUILD_TUPLE); EMIT(load_null); // sentinel indicating empty default keyword args } @@ -1122,7 +1122,7 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) { // build the "fromlist" tuple EMIT_ARG(load_const_str, MP_QSTR__star_); - EMIT_ARG(build_tuple, 1); + EMIT_ARG(build, 1, MP_EMIT_BUILD_TUPLE); // do the import qstr dummy_q; @@ -1141,7 +1141,7 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) { qstr id2 = MP_PARSE_NODE_LEAF_ARG(pns3->nodes[0]); // should be id EMIT_ARG(load_const_str, id2); } - EMIT_ARG(build_tuple, n); + EMIT_ARG(build, n, MP_EMIT_BUILD_TUPLE); // do the import qstr dummy_q; @@ -2397,7 +2397,7 @@ STATIC void compile_atom_paren(compiler_t *comp, mp_parse_node_struct_t *pns) { STATIC void compile_atom_bracket(compiler_t *comp, mp_parse_node_struct_t *pns) { if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { // empty list - EMIT_ARG(build_list, 0); + EMIT_ARG(build, 0, MP_EMIT_BUILD_LIST); } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) { mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)pns->nodes[0]; if (MP_PARSE_NODE_IS_STRUCT(pns2->nodes[1])) { @@ -2406,12 +2406,12 @@ STATIC void compile_atom_bracket(compiler_t *comp, mp_parse_node_struct_t *pns) // list of one item, with trailing comma assert(MP_PARSE_NODE_IS_NULL(pns3->nodes[0])); compile_node(comp, pns2->nodes[0]); - EMIT_ARG(build_list, 1); + EMIT_ARG(build, 1, MP_EMIT_BUILD_LIST); } else if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_testlist_comp_3c) { // list of many items compile_node(comp, pns2->nodes[0]); compile_generic_all_nodes(comp, pns3); - EMIT_ARG(build_list, 1 + MP_PARSE_NODE_STRUCT_NUM_NODES(pns3)); + EMIT_ARG(build, 1 + MP_PARSE_NODE_STRUCT_NUM_NODES(pns3), MP_EMIT_BUILD_LIST); } else if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_comp_for) { // list comprehension compile_comprehension(comp, pns2, SCOPE_LIST_COMP); @@ -2424,12 +2424,12 @@ STATIC void compile_atom_bracket(compiler_t *comp, mp_parse_node_struct_t *pns) list_with_2_items: compile_node(comp, pns2->nodes[0]); compile_node(comp, pns2->nodes[1]); - EMIT_ARG(build_list, 2); + EMIT_ARG(build, 2, MP_EMIT_BUILD_LIST); } } else { // list with 1 item compile_node(comp, pns->nodes[0]); - EMIT_ARG(build_list, 1); + EMIT_ARG(build, 1, MP_EMIT_BUILD_LIST); } } @@ -2437,12 +2437,12 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { mp_parse_node_t pn = pns->nodes[0]; if (MP_PARSE_NODE_IS_NULL(pn)) { // empty dict - EMIT_ARG(build_map, 0); + EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP); } else if (MP_PARSE_NODE_IS_STRUCT(pn)) { pns = (mp_parse_node_struct_t*)pn; if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker_item) { // dict with one element - EMIT_ARG(build_map, 1); + EMIT_ARG(build, 1, MP_EMIT_BUILD_MAP); compile_node(comp, pn); EMIT(store_map); } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker) { @@ -2459,7 +2459,7 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { bool is_dict; if (!MICROPY_PY_BUILTINS_SET || MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_dictorsetmaker_item)) { // a dictionary - EMIT_ARG(build_map, 1 + n); + EMIT_ARG(build, 1 + n, MP_EMIT_BUILD_MAP); compile_node(comp, pns->nodes[0]); EMIT(store_map); is_dict = true; @@ -3040,9 +3040,9 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) { } if (scope->kind == SCOPE_LIST_COMP) { - EMIT_ARG(build_list, 0); + EMIT_ARG(build, 0, MP_EMIT_BUILD_LIST); } else if (scope->kind == SCOPE_DICT_COMP) { - EMIT_ARG(build_map, 0); + EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP); #if MICROPY_PY_BUILTINS_SET } else if (scope->kind == SCOPE_SET_COMP) { EMIT_ARG(build_set, 0); diff --git a/py/emit.h b/py/emit.h index c85df0a675..8caf92882e 100644 --- a/py/emit.h +++ b/py/emit.h @@ -59,6 +59,11 @@ typedef enum { #define MP_EMIT_IDOP_LOCAL_FAST (0) #define MP_EMIT_IDOP_LOCAL_DEREF (1) +// Kind for emit->build() +#define MP_EMIT_BUILD_TUPLE (0) +#define MP_EMIT_BUILD_LIST (1) +#define MP_EMIT_BUILD_MAP (3) + // Kind for emit->yield() #define MP_EMIT_YIELD_VALUE (0) #define MP_EMIT_YIELD_FROM (1) @@ -122,9 +127,7 @@ typedef struct _emit_method_table_t { void (*pop_except)(emit_t *emit); void (*unary_op)(emit_t *emit, mp_unary_op_t op); void (*binary_op)(emit_t *emit, mp_binary_op_t op); - void (*build_tuple)(emit_t *emit, mp_uint_t n_args); - void (*build_list)(emit_t *emit, mp_uint_t n_args); - void (*build_map)(emit_t *emit, mp_uint_t n_args); + void (*build)(emit_t *emit, mp_uint_t n_args, int kind); void (*store_map)(emit_t *emit); #if MICROPY_PY_BUILTINS_SET void (*build_set)(emit_t *emit, mp_uint_t n_args); @@ -236,9 +239,7 @@ void mp_emit_bc_pop_block(emit_t *emit); void mp_emit_bc_pop_except(emit_t *emit); void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op); void mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op); -void mp_emit_bc_build_tuple(emit_t *emit, mp_uint_t n_args); -void mp_emit_bc_build_list(emit_t *emit, mp_uint_t n_args); -void mp_emit_bc_build_map(emit_t *emit, mp_uint_t n_args); +void mp_emit_bc_build(emit_t *emit, mp_uint_t n_args, int kind); void mp_emit_bc_store_map(emit_t *emit); #if MICROPY_PY_BUILTINS_SET void mp_emit_bc_build_set(emit_t *emit, mp_uint_t n_args); diff --git a/py/emitbc.c b/py/emitbc.c index bff2c5a4c5..3cfc059351 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -816,19 +816,16 @@ void mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op) { } } -void mp_emit_bc_build_tuple(emit_t *emit, mp_uint_t n_args) { - emit_bc_pre(emit, 1 - n_args); - emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_TUPLE, n_args); -} - -void mp_emit_bc_build_list(emit_t *emit, mp_uint_t n_args) { - emit_bc_pre(emit, 1 - n_args); - emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_LIST, n_args); -} - -void mp_emit_bc_build_map(emit_t *emit, mp_uint_t n_args) { - emit_bc_pre(emit, 1); - emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_MAP, n_args); +void mp_emit_bc_build(emit_t *emit, mp_uint_t n_args, int kind) { + MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_TUPLE == MP_BC_BUILD_TUPLE); + MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_LIST == MP_BC_BUILD_LIST); + MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_MAP == MP_BC_BUILD_MAP); + if (kind == MP_EMIT_BUILD_MAP) { + emit_bc_pre(emit, 1); + } else { + emit_bc_pre(emit, 1 - n_args); + } + emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_TUPLE + kind, n_args); } void mp_emit_bc_store_map(emit_t *emit) { @@ -1010,9 +1007,7 @@ const emit_method_table_t emit_bc_method_table = { mp_emit_bc_pop_except, mp_emit_bc_unary_op, mp_emit_bc_binary_op, - mp_emit_bc_build_tuple, - mp_emit_bc_build_list, - mp_emit_bc_build_map, + mp_emit_bc_build, mp_emit_bc_store_map, #if MICROPY_PY_BUILTINS_SET mp_emit_bc_build_set, diff --git a/py/emitnative.c b/py/emitnative.c index 26bcebfcbb..3b4e9edb29 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -1923,26 +1923,18 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) { } } -STATIC void emit_native_build_tuple(emit_t *emit, mp_uint_t n_args) { +STATIC void emit_native_build(emit_t *emit, mp_uint_t n_args, int kind) { // for viper: call runtime, with types of args // if wrapped in byte_array, or something, allocates memory and fills it + MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_TUPLE == MP_F_BUILD_TUPLE); + MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_LIST == MP_F_BUILD_LIST); + MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_MAP == MP_F_BUILD_MAP); emit_native_pre(emit); - emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items - emit_call_with_imm_arg(emit, MP_F_BUILD_TUPLE, n_args, REG_ARG_1); - emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new tuple -} - -STATIC void emit_native_build_list(emit_t *emit, mp_uint_t n_args) { - emit_native_pre(emit); - emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items - emit_call_with_imm_arg(emit, MP_F_BUILD_LIST, n_args, REG_ARG_1); - emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new list -} - -STATIC void emit_native_build_map(emit_t *emit, mp_uint_t n_args) { - emit_native_pre(emit); - emit_call_with_imm_arg(emit, MP_F_BUILD_MAP, n_args, REG_ARG_1); - emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new map + if (kind == MP_EMIT_BUILD_TUPLE || kind == MP_EMIT_BUILD_LIST) { + emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items + } + emit_call_with_imm_arg(emit, MP_F_BUILD_TUPLE + kind, n_args, REG_ARG_1); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new tuple/list/map } STATIC void emit_native_store_map(emit_t *emit) { @@ -2255,9 +2247,7 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_pop_except, emit_native_unary_op, emit_native_binary_op, - emit_native_build_tuple, - emit_native_build_list, - emit_native_build_map, + emit_native_build, emit_native_store_map, #if MICROPY_PY_BUILTINS_SET emit_native_build_set, From d298013939b38fb05961cf05c03ac3aef6a4f00c Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 22 May 2018 21:16:30 +1000 Subject: [PATCH 708/828] py/emit: Combine name and global into one func for load/store/delete. Reduces code size by: bare-arm: -56 minimal x86: -300 unix x64: -576 unix nanbox: -300 stm32: -164 cc3200: -56 esp8266: -236 esp32: -76 --- py/compile.c | 4 +- py/emit.h | 16 ++++---- py/emitbc.c | 43 ++++++--------------- py/emitcommon.c | 4 +- py/emitnative.c | 101 ++++++++++++++++++++++++------------------------ 5 files changed, 74 insertions(+), 94 deletions(-) diff --git a/py/compile.c b/py/compile.c index 6f0be8fa8c..3d443c6d88 100644 --- a/py/compile.c +++ b/py/compile.c @@ -66,7 +66,7 @@ typedef enum { #define EMIT(fun) (comp->emit_method_table->fun(comp->emit)) #define EMIT_ARG(fun, ...) (comp->emit_method_table->fun(comp->emit, __VA_ARGS__)) #define EMIT_LOAD_FAST(qst, local_num) (comp->emit_method_table->load_id.local(comp->emit, qst, local_num, MP_EMIT_IDOP_LOCAL_FAST)) -#define EMIT_LOAD_GLOBAL(qst) (comp->emit_method_table->load_id.global(comp->emit, qst)) +#define EMIT_LOAD_GLOBAL(qst) (comp->emit_method_table->load_id.global(comp->emit, qst, MP_EMIT_IDOP_GLOBAL_GLOBAL)) #else @@ -74,7 +74,7 @@ typedef enum { #define EMIT(fun) (mp_emit_bc_##fun(comp->emit)) #define EMIT_ARG(fun, ...) (mp_emit_bc_##fun(comp->emit, __VA_ARGS__)) #define EMIT_LOAD_FAST(qst, local_num) (mp_emit_bc_load_local(comp->emit, qst, local_num, MP_EMIT_IDOP_LOCAL_FAST)) -#define EMIT_LOAD_GLOBAL(qst) (mp_emit_bc_load_global(comp->emit, qst)) +#define EMIT_LOAD_GLOBAL(qst) (mp_emit_bc_load_global(comp->emit, qst, MP_EMIT_IDOP_GLOBAL_GLOBAL)) #endif diff --git a/py/emit.h b/py/emit.h index 8caf92882e..3574d00e3e 100644 --- a/py/emit.h +++ b/py/emit.h @@ -59,6 +59,10 @@ typedef enum { #define MP_EMIT_IDOP_LOCAL_FAST (0) #define MP_EMIT_IDOP_LOCAL_DEREF (1) +// Kind for emit_id_ops->global() +#define MP_EMIT_IDOP_GLOBAL_NAME (0) +#define MP_EMIT_IDOP_GLOBAL_GLOBAL (1) + // Kind for emit->build() #define MP_EMIT_BUILD_TUPLE (0) #define MP_EMIT_BUILD_LIST (1) @@ -72,8 +76,7 @@ typedef struct _emit_t emit_t; typedef struct _mp_emit_method_table_id_ops_t { void (*local)(emit_t *emit, qstr qst, mp_uint_t local_num, int kind); - void (*name)(emit_t *emit, qstr qst); - void (*global)(emit_t *emit, qstr qst); + void (*global)(emit_t *emit, qstr qst, int kind); } mp_emit_method_table_id_ops_t; typedef struct _emit_method_table_t { @@ -190,14 +193,11 @@ void mp_emit_bc_adjust_stack_size(emit_t *emit, mp_int_t delta); void mp_emit_bc_set_source_line(emit_t *emit, mp_uint_t line); void mp_emit_bc_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind); -void mp_emit_bc_load_name(emit_t *emit, qstr qst); -void mp_emit_bc_load_global(emit_t *emit, qstr qst); +void mp_emit_bc_load_global(emit_t *emit, qstr qst, int kind); void mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind); -void mp_emit_bc_store_name(emit_t *emit, qstr qst); -void mp_emit_bc_store_global(emit_t *emit, qstr qst); +void mp_emit_bc_store_global(emit_t *emit, qstr qst, int kind); void mp_emit_bc_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind); -void mp_emit_bc_delete_name(emit_t *emit, qstr qst); -void mp_emit_bc_delete_global(emit_t *emit, qstr qst); +void mp_emit_bc_delete_global(emit_t *emit, qstr qst, int kind); void mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l); void mp_emit_bc_import_name(emit_t *emit, qstr qst); diff --git a/py/emitbc.c b/py/emitbc.c index 3cfc059351..ed043de3a2 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -568,19 +568,12 @@ void mp_emit_bc_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind } } -void mp_emit_bc_load_name(emit_t *emit, qstr qst) { +void mp_emit_bc_load_global(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_BC_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_LOAD_NAME); + MP_STATIC_ASSERT(MP_BC_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_LOAD_GLOBAL); (void)qst; emit_bc_pre(emit, 1); - emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_NAME, qst); - if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { - emit_write_bytecode_byte(emit, 0); - } -} - -void mp_emit_bc_load_global(emit_t *emit, qstr qst) { - (void)qst; - emit_bc_pre(emit, 1); - emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_GLOBAL, qst); + emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_NAME + kind, qst); if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { emit_write_bytecode_byte(emit, 0); } @@ -621,14 +614,11 @@ void mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kin } } -void mp_emit_bc_store_name(emit_t *emit, qstr qst) { +void mp_emit_bc_store_global(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_BC_STORE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_STORE_NAME); + MP_STATIC_ASSERT(MP_BC_STORE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_STORE_GLOBAL); emit_bc_pre(emit, -1); - emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_NAME, qst); -} - -void mp_emit_bc_store_global(emit_t *emit, qstr qst) { - emit_bc_pre(emit, -1); - emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_GLOBAL, qst); + emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_NAME + kind, qst); } void mp_emit_bc_store_attr(emit_t *emit, qstr qst) { @@ -651,14 +641,11 @@ void mp_emit_bc_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int ki emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_FAST + kind, local_num); } -void mp_emit_bc_delete_name(emit_t *emit, qstr qst) { +void mp_emit_bc_delete_global(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_BC_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_DELETE_NAME); + MP_STATIC_ASSERT(MP_BC_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_DELETE_GLOBAL); emit_bc_pre(emit, 0); - emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_NAME, qst); -} - -void mp_emit_bc_delete_global(emit_t *emit, qstr qst) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_GLOBAL, qst); + emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_NAME + kind, qst); } void mp_emit_bc_delete_attr(emit_t *emit, qstr qst) { @@ -954,17 +941,14 @@ const emit_method_table_t emit_bc_method_table = { { mp_emit_bc_load_local, - mp_emit_bc_load_name, mp_emit_bc_load_global, }, { mp_emit_bc_store_local, - mp_emit_bc_store_name, mp_emit_bc_store_global, }, { mp_emit_bc_delete_local, - mp_emit_bc_delete_name, mp_emit_bc_delete_global, }, @@ -1032,19 +1016,16 @@ const emit_method_table_t emit_bc_method_table = { #else const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_load_id_ops = { mp_emit_bc_load_local, - mp_emit_bc_load_name, mp_emit_bc_load_global, }; const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_store_id_ops = { mp_emit_bc_store_local, - mp_emit_bc_store_name, mp_emit_bc_store_global, }; const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_delete_id_ops = { mp_emit_bc_delete_local, - mp_emit_bc_delete_name, mp_emit_bc_delete_global, }; #endif diff --git a/py/emitcommon.c b/py/emitcommon.c index 47fd41ef2e..89cc2c9597 100644 --- a/py/emitcommon.c +++ b/py/emitcommon.c @@ -63,9 +63,9 @@ void mp_emit_common_id_op(emit_t *emit, const mp_emit_method_table_id_ops_t *emi // call the emit backend with the correct code if (id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { - emit_method_table->name(emit, qst); + emit_method_table->global(emit, qst, MP_EMIT_IDOP_GLOBAL_NAME); } else if (id->kind == ID_INFO_KIND_GLOBAL_EXPLICIT) { - emit_method_table->global(emit, qst); + emit_method_table->global(emit, qst, MP_EMIT_IDOP_GLOBAL_GLOBAL); } else if (id->kind == ID_INFO_KIND_LOCAL) { emit_method_table->local(emit, qst, id->local_num, MP_EMIT_IDOP_LOCAL_FAST); } else { diff --git a/py/emitnative.c b/py/emitnative.c index 3b4e9edb29..203cacff43 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -946,33 +946,39 @@ STATIC void emit_native_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, } } -STATIC void emit_native_load_name(emit_t *emit, qstr qst) { - DEBUG_printf("load_name(%s)\n", qstr_str(qst)); +STATIC void emit_native_load_global(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_F_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_F_LOAD_NAME); + MP_STATIC_ASSERT(MP_F_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_F_LOAD_GLOBAL); emit_native_pre(emit); - emit_call_with_imm_arg(emit, MP_F_LOAD_NAME, qst, REG_ARG_1); - emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); -} - -STATIC void emit_native_load_global(emit_t *emit, qstr qst) { - DEBUG_printf("load_global(%s)\n", qstr_str(qst)); - emit_native_pre(emit); - // check for builtin casting operators - if (emit->do_viper_types && qst == MP_QSTR_int) { - emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_INT); - } else if (emit->do_viper_types && qst == MP_QSTR_uint) { - emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_UINT); - } else if (emit->do_viper_types && qst == MP_QSTR_ptr) { - emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR); - } else if (emit->do_viper_types && qst == MP_QSTR_ptr8) { - emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR8); - } else if (emit->do_viper_types && qst == MP_QSTR_ptr16) { - emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR16); - } else if (emit->do_viper_types && qst == MP_QSTR_ptr32) { - emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR32); + if (kind == MP_EMIT_IDOP_GLOBAL_NAME) { + DEBUG_printf("load_name(%s)\n", qstr_str(qst)); } else { - emit_call_with_imm_arg(emit, MP_F_LOAD_GLOBAL, qst, REG_ARG_1); - emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); + DEBUG_printf("load_global(%s)\n", qstr_str(qst)); + if (emit->do_viper_types) { + // check for builtin casting operators + if (qst == MP_QSTR_int) { + emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_INT); + return; + } else if (qst == MP_QSTR_uint) { + emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_UINT); + return; + } else if (qst == MP_QSTR_ptr) { + emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR); + return; + } else if (qst == MP_QSTR_ptr8) { + emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR8); + return; + } else if (qst == MP_QSTR_ptr16) { + emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR16); + return; + } else if (qst == MP_QSTR_ptr32) { + emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR32); + return; + } + } } + emit_call_with_imm_arg(emit, MP_F_LOAD_NAME + kind, qst, REG_ARG_1); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } STATIC void emit_native_load_attr(emit_t *emit, qstr qst) { @@ -1194,25 +1200,25 @@ STATIC void emit_native_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, } } -STATIC void emit_native_store_name(emit_t *emit, qstr qst) { - // mp_store_name, but needs conversion of object (maybe have mp_viper_store_name(obj, type)) - vtype_kind_t vtype; - emit_pre_pop_reg(emit, &vtype, REG_ARG_2); - assert(vtype == VTYPE_PYOBJ); - emit_call_with_imm_arg(emit, MP_F_STORE_NAME, qst, REG_ARG_1); // arg1 = name - emit_post(emit); -} - -STATIC void emit_native_store_global(emit_t *emit, qstr qst) { - vtype_kind_t vtype = peek_vtype(emit, 0); - if (vtype == VTYPE_PYOBJ) { +STATIC void emit_native_store_global(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_F_STORE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_F_STORE_NAME); + MP_STATIC_ASSERT(MP_F_STORE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_F_STORE_GLOBAL); + if (kind == MP_EMIT_IDOP_GLOBAL_NAME) { + // mp_store_name, but needs conversion of object (maybe have mp_viper_store_name(obj, type)) + vtype_kind_t vtype; emit_pre_pop_reg(emit, &vtype, REG_ARG_2); + assert(vtype == VTYPE_PYOBJ); } else { - emit_pre_pop_reg(emit, &vtype, REG_ARG_1); - emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, vtype, REG_ARG_2); // arg2 = type - ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET); + vtype_kind_t vtype = peek_vtype(emit, 0); + if (vtype == VTYPE_PYOBJ) { + emit_pre_pop_reg(emit, &vtype, REG_ARG_2); + } else { + emit_pre_pop_reg(emit, &vtype, REG_ARG_1); + emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, vtype, REG_ARG_2); // arg2 = type + ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET); + } } - emit_call_with_imm_arg(emit, MP_F_STORE_GLOBAL, qst, REG_ARG_1); // arg1 = name + emit_call_with_imm_arg(emit, MP_F_STORE_NAME + kind, qst, REG_ARG_1); // arg1 = name emit_post(emit); } @@ -1417,15 +1423,11 @@ STATIC void emit_native_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num } } -STATIC void emit_native_delete_name(emit_t *emit, qstr qst) { +STATIC void emit_native_delete_global(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_F_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_F_DELETE_NAME); + MP_STATIC_ASSERT(MP_F_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_F_DELETE_GLOBAL); emit_native_pre(emit); - emit_call_with_imm_arg(emit, MP_F_DELETE_NAME, qst, REG_ARG_1); - emit_post(emit); -} - -STATIC void emit_native_delete_global(emit_t *emit, qstr qst) { - emit_native_pre(emit); - emit_call_with_imm_arg(emit, MP_F_DELETE_GLOBAL, qst, REG_ARG_1); + emit_call_with_imm_arg(emit, MP_F_DELETE_NAME + kind, qst, REG_ARG_1); emit_post(emit); } @@ -2194,17 +2196,14 @@ const emit_method_table_t EXPORT_FUN(method_table) = { { emit_native_load_local, - emit_native_load_name, emit_native_load_global, }, { emit_native_store_local, - emit_native_store_name, emit_native_store_global, }, { emit_native_delete_local, - emit_native_delete_name, emit_native_delete_global, }, From a4941a8ba49e3503f1a87f318b79b137a70b803b Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 22 May 2018 21:31:56 +1000 Subject: [PATCH 709/828] py/emit: Combine load/store/delete subscr into one emit function. Reduces code size by: bare-arm: -8 minimal x86: -104 unix x64: -312 unix nanbox: -120 stm32: -60 cc3200: -16 esp8266: -92 esp32: -24 --- py/compile.c | 10 +++++----- py/emit.h | 13 +++++++------ py/emitbc.c | 30 +++++++++++++----------------- py/emitnative.c | 14 +++++++++++--- 4 files changed, 36 insertions(+), 31 deletions(-) diff --git a/py/compile.c b/py/compile.c index 3d443c6d88..6aba2b896e 100644 --- a/py/compile.c +++ b/py/compile.c @@ -366,14 +366,14 @@ STATIC void c_assign_atom_expr(compiler_t *comp, mp_parse_node_struct_t *pns, as if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) { if (assign_kind == ASSIGN_AUG_STORE) { EMIT(rot_three); - EMIT(store_subscr); + EMIT_ARG(subscr, MP_EMIT_SUBSCR_STORE); } else { compile_node(comp, pns1->nodes[0]); if (assign_kind == ASSIGN_AUG_LOAD) { EMIT(dup_top_two); - EMIT(load_subscr); + EMIT_ARG(subscr, MP_EMIT_SUBSCR_LOAD); } else { - EMIT(store_subscr); + EMIT_ARG(subscr, MP_EMIT_SUBSCR_STORE); } } return; @@ -884,7 +884,7 @@ STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) { } if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) { compile_node(comp, pns1->nodes[0]); - EMIT(delete_subscr); + EMIT_ARG(subscr, MP_EMIT_SUBSCR_DELETE); } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_period) { assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0])); EMIT_ARG(delete_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0])); @@ -2536,7 +2536,7 @@ STATIC void compile_trailer_paren(compiler_t *comp, mp_parse_node_struct_t *pns) STATIC void compile_trailer_bracket(compiler_t *comp, mp_parse_node_struct_t *pns) { // object who's index we want is on top of stack compile_node(comp, pns->nodes[0]); // the index - EMIT(load_subscr); + EMIT_ARG(subscr, MP_EMIT_SUBSCR_LOAD); } STATIC void compile_trailer_period(compiler_t *comp, mp_parse_node_struct_t *pns) { diff --git a/py/emit.h b/py/emit.h index 3574d00e3e..6467f84e8f 100644 --- a/py/emit.h +++ b/py/emit.h @@ -63,6 +63,11 @@ typedef enum { #define MP_EMIT_IDOP_GLOBAL_NAME (0) #define MP_EMIT_IDOP_GLOBAL_GLOBAL (1) +// Kind for emit->subscr() +#define MP_EMIT_SUBSCR_LOAD (0) +#define MP_EMIT_SUBSCR_STORE (1) +#define MP_EMIT_SUBSCR_DELETE (2) + // Kind for emit->build() #define MP_EMIT_BUILD_TUPLE (0) #define MP_EMIT_BUILD_LIST (1) @@ -103,11 +108,9 @@ typedef struct _emit_method_table_t { void (*load_attr)(emit_t *emit, qstr qst); void (*load_method)(emit_t *emit, qstr qst, bool is_super); void (*load_build_class)(emit_t *emit); - void (*load_subscr)(emit_t *emit); + void (*subscr)(emit_t *emit, int kind); void (*store_attr)(emit_t *emit, qstr qst); - void (*store_subscr)(emit_t *emit); void (*delete_attr)(emit_t *emit, qstr qst); - void (*delete_subscr)(emit_t *emit); void (*dup_top)(emit_t *emit); void (*dup_top_two)(emit_t *emit); void (*pop_top)(emit_t *emit); @@ -211,11 +214,9 @@ void mp_emit_bc_load_null(emit_t *emit); void mp_emit_bc_load_attr(emit_t *emit, qstr qst); void mp_emit_bc_load_method(emit_t *emit, qstr qst, bool is_super); void mp_emit_bc_load_build_class(emit_t *emit); -void mp_emit_bc_load_subscr(emit_t *emit); +void mp_emit_bc_subscr(emit_t *emit, int kind); void mp_emit_bc_store_attr(emit_t *emit, qstr qst); -void mp_emit_bc_store_subscr(emit_t *emit); void mp_emit_bc_delete_attr(emit_t *emit, qstr qst); -void mp_emit_bc_delete_subscr(emit_t *emit); void mp_emit_bc_dup_top(emit_t *emit); void mp_emit_bc_dup_top_two(emit_t *emit); void mp_emit_bc_pop_top(emit_t *emit); diff --git a/py/emitbc.c b/py/emitbc.c index ed043de3a2..b342c21a41 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -597,9 +597,18 @@ void mp_emit_bc_load_build_class(emit_t *emit) { emit_write_bytecode_byte(emit, MP_BC_LOAD_BUILD_CLASS); } -void mp_emit_bc_load_subscr(emit_t *emit) { - emit_bc_pre(emit, -1); - emit_write_bytecode_byte(emit, MP_BC_LOAD_SUBSCR); +void mp_emit_bc_subscr(emit_t *emit, int kind) { + if (kind == MP_EMIT_SUBSCR_LOAD) { + emit_bc_pre(emit, -1); + emit_write_bytecode_byte(emit, MP_BC_LOAD_SUBSCR); + } else { + if (kind == MP_EMIT_SUBSCR_DELETE) { + mp_emit_bc_load_null(emit); + mp_emit_bc_rot_three(emit); + } + emit_bc_pre(emit, -3); + emit_write_bytecode_byte(emit, MP_BC_STORE_SUBSCR); + } } void mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { @@ -629,11 +638,6 @@ void mp_emit_bc_store_attr(emit_t *emit, qstr qst) { } } -void mp_emit_bc_store_subscr(emit_t *emit) { - emit_bc_pre(emit, -3); - emit_write_bytecode_byte(emit, MP_BC_STORE_SUBSCR); -} - void mp_emit_bc_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { MP_STATIC_ASSERT(MP_BC_DELETE_FAST + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_DELETE_FAST); MP_STATIC_ASSERT(MP_BC_DELETE_FAST + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_DELETE_DEREF); @@ -654,12 +658,6 @@ void mp_emit_bc_delete_attr(emit_t *emit, qstr qst) { mp_emit_bc_store_attr(emit, qst); } -void mp_emit_bc_delete_subscr(emit_t *emit) { - mp_emit_bc_load_null(emit); - mp_emit_bc_rot_three(emit); - mp_emit_bc_store_subscr(emit); -} - void mp_emit_bc_dup_top(emit_t *emit) { emit_bc_pre(emit, 1); emit_write_bytecode_byte(emit, MP_BC_DUP_TOP); @@ -964,11 +962,9 @@ const emit_method_table_t emit_bc_method_table = { mp_emit_bc_load_attr, mp_emit_bc_load_method, mp_emit_bc_load_build_class, - mp_emit_bc_load_subscr, + mp_emit_bc_subscr, mp_emit_bc_store_attr, - mp_emit_bc_store_subscr, mp_emit_bc_delete_attr, - mp_emit_bc_delete_subscr, mp_emit_bc_dup_top, mp_emit_bc_dup_top_two, mp_emit_bc_pop_top, diff --git a/py/emitnative.c b/py/emitnative.c index 203cacff43..725ee21edb 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -1447,6 +1447,16 @@ STATIC void emit_native_delete_subscr(emit_t *emit) { emit_call_with_imm_arg(emit, MP_F_OBJ_SUBSCR, (mp_uint_t)MP_OBJ_NULL, REG_ARG_3); } +STATIC void emit_native_subscr(emit_t *emit, int kind) { + if (kind == MP_EMIT_SUBSCR_LOAD) { + emit_native_load_subscr(emit); + } else if (kind == MP_EMIT_SUBSCR_STORE) { + emit_native_store_subscr(emit); + } else { + emit_native_delete_subscr(emit); + } +} + STATIC void emit_native_dup_top(emit_t *emit) { DEBUG_printf("dup_top\n"); vtype_kind_t vtype; @@ -2219,11 +2229,9 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_load_attr, emit_native_load_method, emit_native_load_build_class, - emit_native_load_subscr, + emit_native_subscr, emit_native_store_attr, - emit_native_store_subscr, emit_native_delete_attr, - emit_native_delete_subscr, emit_native_dup_top, emit_native_dup_top_two, emit_native_pop_top, From 6211d979eed0a809cef03230e14b6d264f6f92ee Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 22 May 2018 21:43:41 +1000 Subject: [PATCH 710/828] py/emit: Combine load/store/delete attr into one emit function. Reduces code size by: bare-arm: -20 minimal x86: -140 unix x64: -408 unix nanbox: -140 stm32: -68 cc3200: -16 esp8266: -80 esp32: -32 --- py/compile.c | 14 +++++++------- py/emit.h | 13 +++++++------ py/emitbc.c | 43 ++++++++++++++++++------------------------- py/emitnative.c | 14 +++++++++++--- 4 files changed, 43 insertions(+), 41 deletions(-) diff --git a/py/compile.c b/py/compile.c index 6aba2b896e..e3735bf3dd 100644 --- a/py/compile.c +++ b/py/compile.c @@ -381,12 +381,12 @@ STATIC void c_assign_atom_expr(compiler_t *comp, mp_parse_node_struct_t *pns, as assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0])); if (assign_kind == ASSIGN_AUG_LOAD) { EMIT(dup_top); - EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0])); + EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]), MP_EMIT_ATTR_LOAD); } else { if (assign_kind == ASSIGN_AUG_STORE) { EMIT(rot_two); } - EMIT_ARG(store_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0])); + EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]), MP_EMIT_ATTR_STORE); } return; } @@ -820,7 +820,7 @@ STATIC void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_node(comp, name_nodes[0]); for (int j = 1; j < name_len; j++) { assert(MP_PARSE_NODE_IS_ID(name_nodes[j])); // should be - EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(name_nodes[j])); + EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(name_nodes[j]), MP_EMIT_ATTR_LOAD); } // nodes[1] contains arguments to the decorator function, if any @@ -887,7 +887,7 @@ STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) { EMIT_ARG(subscr, MP_EMIT_SUBSCR_DELETE); } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_period) { assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0])); - EMIT_ARG(delete_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0])); + EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]), MP_EMIT_ATTR_DELETE); } else { goto cannot_delete; } @@ -1061,7 +1061,7 @@ STATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) { EMIT_ARG(import_name, q_full); if (is_as) { for (int i = 1; i < n; i++) { - EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[i])); + EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]), MP_EMIT_ATTR_LOAD); } } } @@ -1811,7 +1811,7 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_nod // at this point the stack contains: ..., __aexit__, self, exc EMIT(dup_top); #if MICROPY_CPYTHON_COMPAT - EMIT_ARG(load_attr, MP_QSTR___class__); // get type(exc) + EMIT_ARG(attr, MP_QSTR___class__, MP_EMIT_ATTR_LOAD); // get type(exc) #else compile_load_id(comp, MP_QSTR_type); EMIT(rot_two); @@ -2541,7 +2541,7 @@ STATIC void compile_trailer_bracket(compiler_t *comp, mp_parse_node_struct_t *pn STATIC void compile_trailer_period(compiler_t *comp, mp_parse_node_struct_t *pns) { // object who's attribute we want is on top of stack - EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[0])); // attribute to get + EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]), MP_EMIT_ATTR_LOAD); // attribute to get } #if MICROPY_PY_BUILTINS_SLICE diff --git a/py/emit.h b/py/emit.h index 6467f84e8f..c9e4f0c718 100644 --- a/py/emit.h +++ b/py/emit.h @@ -68,6 +68,11 @@ typedef enum { #define MP_EMIT_SUBSCR_STORE (1) #define MP_EMIT_SUBSCR_DELETE (2) +// Kind for emit->attr() +#define MP_EMIT_ATTR_LOAD (0) +#define MP_EMIT_ATTR_STORE (1) +#define MP_EMIT_ATTR_DELETE (2) + // Kind for emit->build() #define MP_EMIT_BUILD_TUPLE (0) #define MP_EMIT_BUILD_LIST (1) @@ -105,12 +110,10 @@ typedef struct _emit_method_table_t { void (*load_const_str)(emit_t *emit, qstr qst); void (*load_const_obj)(emit_t *emit, mp_obj_t obj); void (*load_null)(emit_t *emit); - void (*load_attr)(emit_t *emit, qstr qst); void (*load_method)(emit_t *emit, qstr qst, bool is_super); void (*load_build_class)(emit_t *emit); void (*subscr)(emit_t *emit, int kind); - void (*store_attr)(emit_t *emit, qstr qst); - void (*delete_attr)(emit_t *emit, qstr qst); + void (*attr)(emit_t *emit, qstr qst, int kind); void (*dup_top)(emit_t *emit); void (*dup_top_two)(emit_t *emit); void (*pop_top)(emit_t *emit); @@ -211,12 +214,10 @@ void mp_emit_bc_load_const_small_int(emit_t *emit, mp_int_t arg); void mp_emit_bc_load_const_str(emit_t *emit, qstr qst); void mp_emit_bc_load_const_obj(emit_t *emit, mp_obj_t obj); void mp_emit_bc_load_null(emit_t *emit); -void mp_emit_bc_load_attr(emit_t *emit, qstr qst); void mp_emit_bc_load_method(emit_t *emit, qstr qst, bool is_super); void mp_emit_bc_load_build_class(emit_t *emit); void mp_emit_bc_subscr(emit_t *emit, int kind); -void mp_emit_bc_store_attr(emit_t *emit, qstr qst); -void mp_emit_bc_delete_attr(emit_t *emit, qstr qst); +void mp_emit_bc_attr(emit_t *emit, qstr qst, int kind); void mp_emit_bc_dup_top(emit_t *emit); void mp_emit_bc_dup_top_two(emit_t *emit); void mp_emit_bc_pop_top(emit_t *emit); diff --git a/py/emitbc.c b/py/emitbc.c index b342c21a41..774343f2bf 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -579,14 +579,6 @@ void mp_emit_bc_load_global(emit_t *emit, qstr qst, int kind) { } } -void mp_emit_bc_load_attr(emit_t *emit, qstr qst) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_ATTR, qst); - if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { - emit_write_bytecode_byte(emit, 0); - } -} - void mp_emit_bc_load_method(emit_t *emit, qstr qst, bool is_super) { emit_bc_pre(emit, 1 - 2 * is_super); emit_write_bytecode_byte_qstr(emit, is_super ? MP_BC_LOAD_SUPER_METHOD : MP_BC_LOAD_METHOD, qst); @@ -611,6 +603,23 @@ void mp_emit_bc_subscr(emit_t *emit, int kind) { } } +void mp_emit_bc_attr(emit_t *emit, qstr qst, int kind) { + if (kind == MP_EMIT_ATTR_LOAD) { + emit_bc_pre(emit, 0); + emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_ATTR, qst); + } else { + if (kind == MP_EMIT_ATTR_DELETE) { + mp_emit_bc_load_null(emit); + mp_emit_bc_rot_two(emit); + } + emit_bc_pre(emit, -2); + emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_ATTR, qst); + } + if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { + emit_write_bytecode_byte(emit, 0); + } +} + void mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { MP_STATIC_ASSERT(MP_BC_STORE_FAST_N + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_STORE_FAST_N); MP_STATIC_ASSERT(MP_BC_STORE_FAST_N + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_STORE_DEREF); @@ -630,14 +639,6 @@ void mp_emit_bc_store_global(emit_t *emit, qstr qst, int kind) { emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_NAME + kind, qst); } -void mp_emit_bc_store_attr(emit_t *emit, qstr qst) { - emit_bc_pre(emit, -2); - emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_ATTR, qst); - if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { - emit_write_bytecode_byte(emit, 0); - } -} - void mp_emit_bc_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { MP_STATIC_ASSERT(MP_BC_DELETE_FAST + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_DELETE_FAST); MP_STATIC_ASSERT(MP_BC_DELETE_FAST + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_DELETE_DEREF); @@ -652,12 +653,6 @@ void mp_emit_bc_delete_global(emit_t *emit, qstr qst, int kind) { emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_NAME + kind, qst); } -void mp_emit_bc_delete_attr(emit_t *emit, qstr qst) { - mp_emit_bc_load_null(emit); - mp_emit_bc_rot_two(emit); - mp_emit_bc_store_attr(emit, qst); -} - void mp_emit_bc_dup_top(emit_t *emit) { emit_bc_pre(emit, 1); emit_write_bytecode_byte(emit, MP_BC_DUP_TOP); @@ -959,12 +954,10 @@ const emit_method_table_t emit_bc_method_table = { mp_emit_bc_load_const_str, mp_emit_bc_load_const_obj, mp_emit_bc_load_null, - mp_emit_bc_load_attr, mp_emit_bc_load_method, mp_emit_bc_load_build_class, mp_emit_bc_subscr, - mp_emit_bc_store_attr, - mp_emit_bc_delete_attr, + mp_emit_bc_attr, mp_emit_bc_dup_top, mp_emit_bc_dup_top_two, mp_emit_bc_pop_top, diff --git a/py/emitnative.c b/py/emitnative.c index 725ee21edb..8624680a6d 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -1457,6 +1457,16 @@ STATIC void emit_native_subscr(emit_t *emit, int kind) { } } +STATIC void emit_native_attr(emit_t *emit, qstr qst, int kind) { + if (kind == MP_EMIT_ATTR_LOAD) { + emit_native_load_attr(emit, qst); + } else if (kind == MP_EMIT_ATTR_STORE) { + emit_native_store_attr(emit, qst); + } else { + emit_native_delete_attr(emit, qst); + } +} + STATIC void emit_native_dup_top(emit_t *emit) { DEBUG_printf("dup_top\n"); vtype_kind_t vtype; @@ -2226,12 +2236,10 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_load_const_str, emit_native_load_const_obj, emit_native_load_null, - emit_native_load_attr, emit_native_load_method, emit_native_load_build_class, emit_native_subscr, - emit_native_store_attr, - emit_native_delete_attr, + emit_native_attr, emit_native_dup_top, emit_native_dup_top_two, emit_native_pop_top, From 8a513da5a560e9c6afa5f0a0f8d44c5fb1ed552d Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 22 May 2018 21:50:22 +1000 Subject: [PATCH 711/828] py/emit: Combine break_loop and continue_loop into one emit function. Reduces code size by: bare-arm: +0 minimal x86: +0 unix x64: -80 unix nanbox: +0 stm32: -12 cc3200: +0 esp8266: -28 esp32: +0 --- py/compile.c | 4 ++-- py/emit.h | 5 +---- py/emitbc.c | 1 - py/emitnative.c | 10 ++-------- 4 files changed, 5 insertions(+), 15 deletions(-) diff --git a/py/compile.c b/py/compile.c index e3735bf3dd..411201931a 100644 --- a/py/compile.c +++ b/py/compile.c @@ -950,7 +950,7 @@ STATIC void compile_break_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_syntax_error(comp, (mp_parse_node_t)pns, "'break' outside loop"); } assert(comp->cur_except_level >= comp->break_continue_except_level); - EMIT_ARG(break_loop, comp->break_label, comp->cur_except_level - comp->break_continue_except_level); + EMIT_ARG(unwind_jump, comp->break_label, comp->cur_except_level - comp->break_continue_except_level); } STATIC void compile_continue_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { @@ -958,7 +958,7 @@ STATIC void compile_continue_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) compile_syntax_error(comp, (mp_parse_node_t)pns, "'continue' outside loop"); } assert(comp->cur_except_level >= comp->break_continue_except_level); - EMIT_ARG(continue_loop, comp->continue_label, comp->cur_except_level - comp->break_continue_except_level); + EMIT_ARG(unwind_jump, comp->continue_label, comp->cur_except_level - comp->break_continue_except_level); } STATIC void compile_return_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { diff --git a/py/emit.h b/py/emit.h index c9e4f0c718..4fd115e230 100644 --- a/py/emit.h +++ b/py/emit.h @@ -122,8 +122,7 @@ typedef struct _emit_method_table_t { void (*jump)(emit_t *emit, mp_uint_t label); void (*pop_jump_if)(emit_t *emit, bool cond, mp_uint_t label); void (*jump_if_or_pop)(emit_t *emit, bool cond, mp_uint_t label); - void (*break_loop)(emit_t *emit, mp_uint_t label, mp_uint_t except_depth); - void (*continue_loop)(emit_t *emit, mp_uint_t label, mp_uint_t except_depth); + void (*unwind_jump)(emit_t *emit, mp_uint_t label, mp_uint_t except_depth); void (*setup_with)(emit_t *emit, mp_uint_t label); void (*with_cleanup)(emit_t *emit, mp_uint_t label); void (*setup_except)(emit_t *emit, mp_uint_t label); @@ -227,8 +226,6 @@ void mp_emit_bc_jump(emit_t *emit, mp_uint_t label); void mp_emit_bc_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label); void mp_emit_bc_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label); void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth); -#define mp_emit_bc_break_loop mp_emit_bc_unwind_jump -#define mp_emit_bc_continue_loop mp_emit_bc_unwind_jump void mp_emit_bc_setup_with(emit_t *emit, mp_uint_t label); void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label); void mp_emit_bc_setup_except(emit_t *emit, mp_uint_t label); diff --git a/py/emitbc.c b/py/emitbc.c index 774343f2bf..6f55303667 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -967,7 +967,6 @@ const emit_method_table_t emit_bc_method_table = { mp_emit_bc_pop_jump_if, mp_emit_bc_jump_if_or_pop, mp_emit_bc_unwind_jump, - mp_emit_bc_unwind_jump, mp_emit_bc_setup_with, mp_emit_bc_with_cleanup, mp_emit_bc_setup_except, diff --git a/py/emitnative.c b/py/emitnative.c index 8624680a6d..b4a3f987c7 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -1560,16 +1560,11 @@ STATIC void emit_native_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label) emit_post(emit); } -STATIC void emit_native_break_loop(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) { +STATIC void emit_native_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) { (void)except_depth; emit_native_jump(emit, label & ~MP_EMIT_BREAK_FROM_FOR); // TODO properly } -STATIC void emit_native_continue_loop(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) { - (void)except_depth; - emit_native_jump(emit, label); // TODO properly -} - STATIC void emit_native_setup_with(emit_t *emit, mp_uint_t label) { // the context manager is on the top of the stack // stack: (..., ctx_mgr) @@ -2248,8 +2243,7 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_jump, emit_native_pop_jump_if, emit_native_jump_if_or_pop, - emit_native_break_loop, - emit_native_continue_loop, + emit_native_unwind_jump, emit_native_setup_with, emit_native_with_cleanup, emit_native_setup_except, From d97906ca9a0f1e0728cefb930d458bb8fba3bd17 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 22 May 2018 21:58:25 +1000 Subject: [PATCH 712/828] py/emit: Combine import from/name/star into one emit function. Change in code size is: bare-arm: +4 minimal x86: -88 unix x64: -456 unix nanbox: -88 stm32: -44 cc3200: +0 esp8266: -104 esp32: +8 --- py/compile.c | 10 +++++----- py/emit.h | 13 +++++++------ py/emitbc.c | 30 ++++++++++++++---------------- py/emitnative.c | 14 +++++++++++--- 4 files changed, 37 insertions(+), 30 deletions(-) diff --git a/py/compile.c b/py/compile.c index 411201931a..1789530f6e 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1024,14 +1024,14 @@ STATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) { if (MP_PARSE_NODE_IS_NULL(pn)) { // empty name (eg, from . import x) *q_base = MP_QSTR_; - EMIT_ARG(import_name, MP_QSTR_); // import the empty string + EMIT_ARG(import, MP_QSTR_, MP_EMIT_IMPORT_NAME); // import the empty string } else if (MP_PARSE_NODE_IS_ID(pn)) { // just a simple name qstr q_full = MP_PARSE_NODE_LEAF_ARG(pn); if (!is_as) { *q_base = q_full; } - EMIT_ARG(import_name, q_full); + EMIT_ARG(import, q_full, MP_EMIT_IMPORT_NAME); } else { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_dotted_name)); // should be mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; @@ -1058,7 +1058,7 @@ STATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) { } qstr q_full = qstr_from_strn(q_ptr, len); mp_local_free(q_ptr); - EMIT_ARG(import_name, q_full); + EMIT_ARG(import, q_full, MP_EMIT_IMPORT_NAME); if (is_as) { for (int i = 1; i < n; i++) { EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]), MP_EMIT_ATTR_LOAD); @@ -1127,7 +1127,7 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) { // do the import qstr dummy_q; do_import_name(comp, pn_import_source, &dummy_q); - EMIT(import_star); + EMIT_ARG(import, MP_QSTR_NULL, MP_EMIT_IMPORT_STAR); } else { EMIT_ARG(load_const_small_int, import_level); @@ -1150,7 +1150,7 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_nodes[i], PN_import_as_name)); mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t*)pn_nodes[i]; qstr id2 = MP_PARSE_NODE_LEAF_ARG(pns3->nodes[0]); // should be id - EMIT_ARG(import_from, id2); + EMIT_ARG(import, id2, MP_EMIT_IMPORT_FROM); if (MP_PARSE_NODE_IS_NULL(pns3->nodes[1])) { compile_store_id(comp, id2); } else { diff --git a/py/emit.h b/py/emit.h index 4fd115e230..d6ebcf791a 100644 --- a/py/emit.h +++ b/py/emit.h @@ -63,6 +63,11 @@ typedef enum { #define MP_EMIT_IDOP_GLOBAL_NAME (0) #define MP_EMIT_IDOP_GLOBAL_GLOBAL (1) +// Kind for emit->import() +#define MP_EMIT_IMPORT_NAME (0) +#define MP_EMIT_IMPORT_FROM (1) +#define MP_EMIT_IMPORT_STAR (2) + // Kind for emit->subscr() #define MP_EMIT_SUBSCR_LOAD (0) #define MP_EMIT_SUBSCR_STORE (1) @@ -102,9 +107,7 @@ typedef struct _emit_method_table_t { mp_emit_method_table_id_ops_t delete_id; void (*label_assign)(emit_t *emit, mp_uint_t l); - void (*import_name)(emit_t *emit, qstr qst); - void (*import_from)(emit_t *emit, qstr qst); - void (*import_star)(emit_t *emit); + void (*import)(emit_t *emit, qstr qst, int kind); void (*load_const_tok)(emit_t *emit, mp_token_kind_t tok); void (*load_const_small_int)(emit_t *emit, mp_int_t arg); void (*load_const_str)(emit_t *emit, qstr qst); @@ -205,9 +208,7 @@ void mp_emit_bc_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int ki void mp_emit_bc_delete_global(emit_t *emit, qstr qst, int kind); void mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l); -void mp_emit_bc_import_name(emit_t *emit, qstr qst); -void mp_emit_bc_import_from(emit_t *emit, qstr qst); -void mp_emit_bc_import_star(emit_t *emit); +void mp_emit_bc_import(emit_t *emit, qstr qst, int kind); void mp_emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok); void mp_emit_bc_load_const_small_int(emit_t *emit, mp_int_t arg); void mp_emit_bc_load_const_str(emit_t *emit, qstr qst); diff --git a/py/emitbc.c b/py/emitbc.c index 6f55303667..6be9f900c7 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -504,19 +504,19 @@ void mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l) { } } -void mp_emit_bc_import_name(emit_t *emit, qstr qst) { - emit_bc_pre(emit, -1); - emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_NAME, qst); -} - -void mp_emit_bc_import_from(emit_t *emit, qstr qst) { - emit_bc_pre(emit, 1); - emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_FROM, qst); -} - -void mp_emit_bc_import_star(emit_t *emit) { - emit_bc_pre(emit, -1); - emit_write_bytecode_byte(emit, MP_BC_IMPORT_STAR); +void mp_emit_bc_import(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_BC_IMPORT_NAME + MP_EMIT_IMPORT_NAME == MP_BC_IMPORT_NAME); + MP_STATIC_ASSERT(MP_BC_IMPORT_NAME + MP_EMIT_IMPORT_FROM == MP_BC_IMPORT_FROM); + if (kind == MP_EMIT_IMPORT_FROM) { + emit_bc_pre(emit, 1); + } else { + emit_bc_pre(emit, -1); + } + if (kind == MP_EMIT_IMPORT_STAR) { + emit_write_bytecode_byte(emit, MP_BC_IMPORT_STAR); + } else { + emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_NAME + kind, qst); + } } void mp_emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) { @@ -946,9 +946,7 @@ const emit_method_table_t emit_bc_method_table = { }, mp_emit_bc_label_assign, - mp_emit_bc_import_name, - mp_emit_bc_import_from, - mp_emit_bc_import_star, + mp_emit_bc_import, mp_emit_bc_load_const_tok, mp_emit_bc_load_const_small_int, mp_emit_bc_load_const_str, diff --git a/py/emitnative.c b/py/emitnative.c index b4a3f987c7..e06198bc94 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -837,6 +837,16 @@ STATIC void emit_native_import_star(emit_t *emit) { emit_post(emit); } +STATIC void emit_native_import(emit_t *emit, qstr qst, int kind) { + if (kind == MP_EMIT_IMPORT_NAME) { + emit_native_import_name(emit, qst); + } else if (kind == MP_EMIT_IMPORT_FROM) { + emit_native_import_from(emit, qst); + } else { + emit_native_import_star(emit); + } +} + STATIC void emit_native_load_const_tok(emit_t *emit, mp_token_kind_t tok) { DEBUG_printf("load_const_tok(tok=%u)\n", tok); emit_native_pre(emit); @@ -2223,9 +2233,7 @@ const emit_method_table_t EXPORT_FUN(method_table) = { }, emit_native_label_assign, - emit_native_import_name, - emit_native_import_from, - emit_native_import_star, + emit_native_import, emit_native_load_const_tok, emit_native_load_const_small_int, emit_native_load_const_str, From 436e0d4c54ab22050072d392f0822e555bcc70f1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 22 May 2018 22:18:42 +1000 Subject: [PATCH 713/828] py/emit: Merge build set/slice into existing build emit function. Reduces code size by: bare-arm: +0 minimal x86: +0 unix x64: -368 unix nanbox: -248 stm32: -128 cc3200: -48 esp8266: -184 esp32: -40 --- py/compile.c | 20 ++++++++++---------- py/emit.h | 14 ++------------ py/emitbc.c | 22 ++-------------------- py/emitnative.c | 30 +++++++++++++----------------- py/nativeglue.c | 2 +- py/runtime0.h | 2 +- 6 files changed, 29 insertions(+), 61 deletions(-) diff --git a/py/compile.c b/py/compile.c index 1789530f6e..be1fd8b1f9 100644 --- a/py/compile.c +++ b/py/compile.c @@ -2499,7 +2499,7 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { #if MICROPY_PY_BUILTINS_SET // if it's a set, build it if (!is_dict) { - EMIT_ARG(build_set, 1 + n); + EMIT_ARG(build, 1 + n, MP_EMIT_BUILD_SET); } #endif } else { @@ -2522,7 +2522,7 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { set_with_one_element: #if MICROPY_PY_BUILTINS_SET compile_node(comp, pn); - EMIT_ARG(build_set, 1); + EMIT_ARG(build, 1, MP_EMIT_BUILD_SET); #else assert(0); #endif @@ -2551,7 +2551,7 @@ STATIC void compile_subscript_3_helper(compiler_t *comp, mp_parse_node_struct_t if (MP_PARSE_NODE_IS_NULL(pn)) { // [?:] EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); - EMIT_ARG(build_slice, 2); + EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE); } else if (MP_PARSE_NODE_IS_STRUCT(pn)) { pns = (mp_parse_node_struct_t*)pn; if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_3c) { @@ -2559,11 +2559,11 @@ STATIC void compile_subscript_3_helper(compiler_t *comp, mp_parse_node_struct_t pn = pns->nodes[0]; if (MP_PARSE_NODE_IS_NULL(pn)) { // [?::] - EMIT_ARG(build_slice, 2); + EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE); } else { // [?::x] compile_node(comp, pn); - EMIT_ARG(build_slice, 3); + EMIT_ARG(build, 3, MP_EMIT_BUILD_SLICE); } } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_3d) { compile_node(comp, pns->nodes[0]); @@ -2572,21 +2572,21 @@ STATIC void compile_subscript_3_helper(compiler_t *comp, mp_parse_node_struct_t assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_sliceop); // should always be if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { // [?:x:] - EMIT_ARG(build_slice, 2); + EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE); } else { // [?:x:x] compile_node(comp, pns->nodes[0]); - EMIT_ARG(build_slice, 3); + EMIT_ARG(build, 3, MP_EMIT_BUILD_SLICE); } } else { // [?:x] compile_node(comp, pn); - EMIT_ARG(build_slice, 2); + EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE); } } else { // [?:x] compile_node(comp, pn); - EMIT_ARG(build_slice, 2); + EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE); } } @@ -3045,7 +3045,7 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) { EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP); #if MICROPY_PY_BUILTINS_SET } else if (scope->kind == SCOPE_SET_COMP) { - EMIT_ARG(build_set, 0); + EMIT_ARG(build, 0, MP_EMIT_BUILD_SET); #endif } diff --git a/py/emit.h b/py/emit.h index d6ebcf791a..7f0d8c0f72 100644 --- a/py/emit.h +++ b/py/emit.h @@ -82,6 +82,8 @@ typedef enum { #define MP_EMIT_BUILD_TUPLE (0) #define MP_EMIT_BUILD_LIST (1) #define MP_EMIT_BUILD_MAP (3) +#define MP_EMIT_BUILD_SET (6) +#define MP_EMIT_BUILD_SLICE (8) // Kind for emit->yield() #define MP_EMIT_YIELD_VALUE (0) @@ -140,12 +142,6 @@ typedef struct _emit_method_table_t { void (*binary_op)(emit_t *emit, mp_binary_op_t op); void (*build)(emit_t *emit, mp_uint_t n_args, int kind); void (*store_map)(emit_t *emit); - #if MICROPY_PY_BUILTINS_SET - void (*build_set)(emit_t *emit, mp_uint_t n_args); - #endif - #if MICROPY_PY_BUILTINS_SLICE - void (*build_slice)(emit_t *emit, mp_uint_t n_args); - #endif void (*store_comp)(emit_t *emit, scope_kind_t kind, mp_uint_t set_stack_index); void (*unpack_sequence)(emit_t *emit, mp_uint_t n_args); void (*unpack_ex)(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right); @@ -241,12 +237,6 @@ void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op); void mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op); void mp_emit_bc_build(emit_t *emit, mp_uint_t n_args, int kind); void mp_emit_bc_store_map(emit_t *emit); -#if MICROPY_PY_BUILTINS_SET -void mp_emit_bc_build_set(emit_t *emit, mp_uint_t n_args); -#endif -#if MICROPY_PY_BUILTINS_SLICE -void mp_emit_bc_build_slice(emit_t *emit, mp_uint_t n_args); -#endif void mp_emit_bc_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t list_stack_index); void mp_emit_bc_unpack_sequence(emit_t *emit, mp_uint_t n_args); void mp_emit_bc_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right); diff --git a/py/emitbc.c b/py/emitbc.c index 6be9f900c7..4c587c72e3 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -800,6 +800,8 @@ void mp_emit_bc_build(emit_t *emit, mp_uint_t n_args, int kind) { MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_TUPLE == MP_BC_BUILD_TUPLE); MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_LIST == MP_BC_BUILD_LIST); MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_MAP == MP_BC_BUILD_MAP); + MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_SET == MP_BC_BUILD_SET); + MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_SLICE == MP_BC_BUILD_SLICE); if (kind == MP_EMIT_BUILD_MAP) { emit_bc_pre(emit, 1); } else { @@ -813,20 +815,6 @@ void mp_emit_bc_store_map(emit_t *emit) { emit_write_bytecode_byte(emit, MP_BC_STORE_MAP); } -#if MICROPY_PY_BUILTINS_SET -void mp_emit_bc_build_set(emit_t *emit, mp_uint_t n_args) { - emit_bc_pre(emit, 1 - n_args); - emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_SET, n_args); -} -#endif - -#if MICROPY_PY_BUILTINS_SLICE -void mp_emit_bc_build_slice(emit_t *emit, mp_uint_t n_args) { - emit_bc_pre(emit, 1 - n_args); - emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_SLICE, n_args); -} -#endif - void mp_emit_bc_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t collection_stack_index) { int t; int n; @@ -979,12 +967,6 @@ const emit_method_table_t emit_bc_method_table = { mp_emit_bc_binary_op, mp_emit_bc_build, mp_emit_bc_store_map, - #if MICROPY_PY_BUILTINS_SET - mp_emit_bc_build_set, - #endif - #if MICROPY_PY_BUILTINS_SLICE - mp_emit_bc_build_slice, - #endif mp_emit_bc_store_comp, mp_emit_bc_unpack_sequence, mp_emit_bc_unpack_ex, diff --git a/py/emitnative.c b/py/emitnative.c index e06198bc94..331e4cf18e 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -1950,18 +1950,29 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) { } } +#if MICROPY_PY_BUILTINS_SLICE +STATIC void emit_native_build_slice(emit_t *emit, mp_uint_t n_args); +#endif + STATIC void emit_native_build(emit_t *emit, mp_uint_t n_args, int kind) { // for viper: call runtime, with types of args // if wrapped in byte_array, or something, allocates memory and fills it MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_TUPLE == MP_F_BUILD_TUPLE); MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_LIST == MP_F_BUILD_LIST); MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_MAP == MP_F_BUILD_MAP); + MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_SET == MP_F_BUILD_SET); + #if MICROPY_PY_BUILTINS_SLICE + if (kind == MP_EMIT_BUILD_SLICE) { + emit_native_build_slice(emit, n_args); + return; + } + #endif emit_native_pre(emit); - if (kind == MP_EMIT_BUILD_TUPLE || kind == MP_EMIT_BUILD_LIST) { + if (kind == MP_EMIT_BUILD_TUPLE || kind == MP_EMIT_BUILD_LIST || kind == MP_EMIT_BUILD_SET) { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items } emit_call_with_imm_arg(emit, MP_F_BUILD_TUPLE + kind, n_args, REG_ARG_1); - emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new tuple/list/map + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new tuple/list/map/set } STATIC void emit_native_store_map(emit_t *emit) { @@ -1974,15 +1985,6 @@ STATIC void emit_native_store_map(emit_t *emit) { emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // map } -#if MICROPY_PY_BUILTINS_SET -STATIC void emit_native_build_set(emit_t *emit, mp_uint_t n_args) { - emit_native_pre(emit); - emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items - emit_call_with_imm_arg(emit, MP_F_BUILD_SET, n_args, REG_ARG_1); - emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new set -} -#endif - #if MICROPY_PY_BUILTINS_SLICE STATIC void emit_native_build_slice(emit_t *emit, mp_uint_t n_args) { DEBUG_printf("build_slice %d\n", n_args); @@ -2266,12 +2268,6 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_binary_op, emit_native_build, emit_native_store_map, - #if MICROPY_PY_BUILTINS_SET - emit_native_build_set, - #endif - #if MICROPY_PY_BUILTINS_SLICE - emit_native_build_slice, - #endif emit_native_store_comp, emit_native_unpack_sequence, emit_native_unpack_ex, diff --git a/py/nativeglue.c b/py/nativeglue.c index e63c2fcda6..b87da6931e 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -146,8 +146,8 @@ void *const mp_fun_table[MP_F_NUMBER_OF] = { mp_obj_new_dict, mp_obj_dict_store, #if MICROPY_PY_BUILTINS_SET - mp_obj_new_set, mp_obj_set_store, + mp_obj_new_set, #endif mp_make_function_from_raw_code, mp_native_call_function_n_kw, diff --git a/py/runtime0.h b/py/runtime0.h index 960532d176..2e89de9f41 100644 --- a/py/runtime0.h +++ b/py/runtime0.h @@ -164,8 +164,8 @@ typedef enum { MP_F_BUILD_MAP, MP_F_STORE_MAP, #if MICROPY_PY_BUILTINS_SET - MP_F_BUILD_SET, MP_F_STORE_SET, + MP_F_BUILD_SET, #endif MP_F_MAKE_FUNCTION_FROM_RAW_CODE, MP_F_NATIVE_CALL_FUNCTION_N_KW, From 18e6358480e640fd94a9383d5fa7d9b8cc2b9f73 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 22 May 2018 22:33:26 +1000 Subject: [PATCH 714/828] py/emit: Combine setup with/except/finally into one emit function. This patch reduces code size by: bare-arm: -16 minimal x86: -156 unix x64: -288 unix nanbox: -184 stm32: -48 cc3200: -16 esp8266: -96 esp32: -16 The last 10 patches combined reduce code size by: bare-arm: -164 minimal x86: -1260 unix x64: -3416 unix nanbox: -1616 stm32: -676 cc3200: -232 esp8266: -1144 esp32: -268 --- py/compile.c | 14 +++++++------- py/emit.h | 13 +++++++------ py/emitbc.c | 29 ++++++++++++----------------- py/emitnative.c | 33 ++++++++++++++++----------------- 4 files changed, 42 insertions(+), 47 deletions(-) diff --git a/py/compile.c b/py/compile.c index be1fd8b1f9..c62ed057dd 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1516,7 +1516,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_ uint l1 = comp_next_label(comp); uint success_label = comp_next_label(comp); - EMIT_ARG(setup_except, l1); + EMIT_ARG(setup_block, l1, MP_EMIT_SETUP_BLOCK_EXCEPT); compile_increase_except_level(comp); compile_node(comp, pn_body); // body @@ -1571,7 +1571,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_ uint l3 = 0; if (qstr_exception_local != 0) { l3 = comp_next_label(comp); - EMIT_ARG(setup_finally, l3); + EMIT_ARG(setup_block, l3, MP_EMIT_SETUP_BLOCK_FINALLY); compile_increase_except_level(comp); } compile_node(comp, pns_except->nodes[1]); @@ -1606,7 +1606,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_ STATIC void compile_try_finally(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_except, mp_parse_node_t pn_else, mp_parse_node_t pn_finally) { uint l_finally_block = comp_next_label(comp); - EMIT_ARG(setup_finally, l_finally_block); + EMIT_ARG(setup_block, l_finally_block, MP_EMIT_SETUP_BLOCK_FINALLY); compile_increase_except_level(comp); if (n_except == 0) { @@ -1668,12 +1668,12 @@ STATIC void compile_with_stmt_helper(compiler_t *comp, int n, mp_parse_node_t *n // this pre-bit is of the form "a as b" mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)nodes[0]; compile_node(comp, pns->nodes[0]); - EMIT_ARG(setup_with, l_end); + EMIT_ARG(setup_block, l_end, MP_EMIT_SETUP_BLOCK_WITH); c_assign(comp, pns->nodes[1], ASSIGN_STORE); } else { // this pre-bit is just an expression compile_node(comp, nodes[0]); - EMIT_ARG(setup_with, l_end); + EMIT_ARG(setup_block, l_end, MP_EMIT_SETUP_BLOCK_WITH); EMIT(pop_top); } compile_increase_except_level(comp); @@ -1726,7 +1726,7 @@ STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns EMIT_ARG(label_assign, continue_label); - EMIT_ARG(setup_except, try_exception_label); + EMIT_ARG(setup_block, try_exception_label, MP_EMIT_SETUP_BLOCK_EXCEPT); compile_increase_except_level(comp); compile_load_id(comp, context); @@ -1797,7 +1797,7 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_nod compile_load_id(comp, context); EMIT_ARG(load_method, MP_QSTR___aexit__, false); - EMIT_ARG(setup_except, try_exception_label); + EMIT_ARG(setup_block, try_exception_label, MP_EMIT_SETUP_BLOCK_EXCEPT); compile_increase_except_level(comp); // compile additional pre-bits and the body compile_async_with_stmt_helper(comp, n - 1, nodes + 1, body); diff --git a/py/emit.h b/py/emit.h index 7f0d8c0f72..aa98efa774 100644 --- a/py/emit.h +++ b/py/emit.h @@ -78,6 +78,11 @@ typedef enum { #define MP_EMIT_ATTR_STORE (1) #define MP_EMIT_ATTR_DELETE (2) +// Kind for emit->setup_block() +#define MP_EMIT_SETUP_BLOCK_WITH (0) +#define MP_EMIT_SETUP_BLOCK_EXCEPT (2) +#define MP_EMIT_SETUP_BLOCK_FINALLY (3) + // Kind for emit->build() #define MP_EMIT_BUILD_TUPLE (0) #define MP_EMIT_BUILD_LIST (1) @@ -128,10 +133,8 @@ typedef struct _emit_method_table_t { void (*pop_jump_if)(emit_t *emit, bool cond, mp_uint_t label); void (*jump_if_or_pop)(emit_t *emit, bool cond, mp_uint_t label); void (*unwind_jump)(emit_t *emit, mp_uint_t label, mp_uint_t except_depth); - void (*setup_with)(emit_t *emit, mp_uint_t label); + void (*setup_block)(emit_t *emit, mp_uint_t label, int kind); void (*with_cleanup)(emit_t *emit, mp_uint_t label); - void (*setup_except)(emit_t *emit, mp_uint_t label); - void (*setup_finally)(emit_t *emit, mp_uint_t label); void (*end_finally)(emit_t *emit); void (*get_iter)(emit_t *emit, bool use_stack); void (*for_iter)(emit_t *emit, mp_uint_t label); @@ -223,10 +226,8 @@ void mp_emit_bc_jump(emit_t *emit, mp_uint_t label); void mp_emit_bc_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label); void mp_emit_bc_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label); void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth); -void mp_emit_bc_setup_with(emit_t *emit, mp_uint_t label); +void mp_emit_bc_setup_block(emit_t *emit, mp_uint_t label, int kind); void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label); -void mp_emit_bc_setup_except(emit_t *emit, mp_uint_t label); -void mp_emit_bc_setup_finally(emit_t *emit, mp_uint_t label); void mp_emit_bc_end_finally(emit_t *emit); void mp_emit_bc_get_iter(emit_t *emit, bool use_stack); void mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label); diff --git a/py/emitbc.c b/py/emitbc.c index 4c587c72e3..f3951e9cb5 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -719,11 +719,18 @@ void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_dept } } -void mp_emit_bc_setup_with(emit_t *emit, mp_uint_t label) { +void mp_emit_bc_setup_block(emit_t *emit, mp_uint_t label, int kind) { + MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_WITH == MP_BC_SETUP_WITH); + MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_EXCEPT == MP_BC_SETUP_EXCEPT); + MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_FINALLY == MP_BC_SETUP_FINALLY); + if (kind == MP_EMIT_SETUP_BLOCK_WITH) { // The SETUP_WITH opcode pops ctx_mgr from the top of the stack // and then pushes 3 entries: __exit__, ctx_mgr, as_value. - emit_bc_pre(emit, 2); - emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_WITH, label); + emit_bc_pre(emit, 2); + } else { + emit_bc_pre(emit, 0); + } + emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_WITH + kind, label); } void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label) { @@ -732,17 +739,7 @@ void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label) { mp_emit_bc_label_assign(emit, label); emit_bc_pre(emit, 2); // ensure we have enough stack space to call the __exit__ method emit_write_bytecode_byte(emit, MP_BC_WITH_CLEANUP); - emit_bc_pre(emit, -4); // cancel the 2 above, plus the 2 from mp_emit_bc_setup_with -} - -void mp_emit_bc_setup_except(emit_t *emit, mp_uint_t label) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_EXCEPT, label); -} - -void mp_emit_bc_setup_finally(emit_t *emit, mp_uint_t label) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_FINALLY, label); + emit_bc_pre(emit, -4); // cancel the 2 above, plus the 2 from mp_emit_bc_setup_block(MP_EMIT_SETUP_BLOCK_WITH) } void mp_emit_bc_end_finally(emit_t *emit) { @@ -953,10 +950,8 @@ const emit_method_table_t emit_bc_method_table = { mp_emit_bc_pop_jump_if, mp_emit_bc_jump_if_or_pop, mp_emit_bc_unwind_jump, - mp_emit_bc_setup_with, + mp_emit_bc_setup_block, mp_emit_bc_with_cleanup, - mp_emit_bc_setup_except, - mp_emit_bc_setup_finally, mp_emit_bc_end_finally, mp_emit_bc_get_iter, mp_emit_bc_for_iter, diff --git a/py/emitnative.c b/py/emitnative.c index 331e4cf18e..ad8f04aac7 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -1617,6 +1617,21 @@ STATIC void emit_native_setup_with(emit_t *emit, mp_uint_t label) { // stack: (..., __exit__, self, as_value, nlr_buf, as_value) } +STATIC void emit_native_setup_block(emit_t *emit, mp_uint_t label, int kind) { + if (kind == MP_EMIT_SETUP_BLOCK_WITH) { + emit_native_setup_with(emit, label); + } else { + // Set up except and finally + emit_native_pre(emit); + // need to commit stack because we may jump elsewhere + need_stack_settled(emit); + emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_1, sizeof(nlr_buf_t) / sizeof(mp_uint_t)); // arg1 = pointer to nlr buf + emit_call(emit, MP_F_NLR_PUSH); + ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label); + emit_post(emit); + } +} + STATIC void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) { // note: label+1 is available as an auxiliary label @@ -1686,20 +1701,6 @@ STATIC void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) { emit_native_label_assign(emit, label + 1); } -STATIC void emit_native_setup_except(emit_t *emit, mp_uint_t label) { - emit_native_pre(emit); - // need to commit stack because we may jump elsewhere - need_stack_settled(emit); - emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_1, sizeof(nlr_buf_t) / sizeof(mp_uint_t)); // arg1 = pointer to nlr buf - emit_call(emit, MP_F_NLR_PUSH); - ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label); - emit_post(emit); -} - -STATIC void emit_native_setup_finally(emit_t *emit, mp_uint_t label) { - emit_native_setup_except(emit, label); -} - STATIC void emit_native_end_finally(emit_t *emit) { // logic: // exc = pop_stack @@ -2254,10 +2255,8 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_pop_jump_if, emit_native_jump_if_or_pop, emit_native_unwind_jump, - emit_native_setup_with, + emit_native_setup_block, emit_native_with_cleanup, - emit_native_setup_except, - emit_native_setup_finally, emit_native_end_finally, emit_native_get_iter, emit_native_for_iter, From df9b7e8f24384df446c98c10b28f4fb143d66d61 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 23 May 2018 12:57:50 +1000 Subject: [PATCH 715/828] esp32/esp32.custom_common.ld: Put soc code in iram0. This is what the IDF does, it must be done. --- ports/esp32/esp32.custom_common.ld | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/esp32/esp32.custom_common.ld b/ports/esp32/esp32.custom_common.ld index c9a61f0184..f49ff9b207 100644 --- a/ports/esp32/esp32.custom_common.ld +++ b/ports/esp32/esp32.custom_common.ld @@ -90,7 +90,7 @@ SECTIONS *app_trace/*(.literal .text .literal.* .text.*) *xtensa-debug-module/eri.o(.literal .text .literal.* .text.*) *librtc.a:(.literal .text .literal.* .text.*) - *libsoc.a:(.literal .text .literal.* .text.*) + *soc/esp32/*(.literal .text .literal.* .text.*) *libhal.a:(.literal .text .literal.* .text.*) *libgcc.a:lib2funcs.o(.literal .text .literal.* .text.*) *spi_flash/spi_flash_rom_patch.o(.literal .text .literal.* .text.*) From 4200018a05bcf7005c467245eb6c136f4fff9651 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 24 May 2018 11:28:54 +1000 Subject: [PATCH 716/828] stm32: Remove unneeded HTML release notes from usbdev and usbhost dirs. These files provide no additional information, all the version and license information is captured in the relevant files in these subdirectories. Thanks to @JoeSc for the original patch. --- ports/stm32/usbdev/Release_Notes.html | 974 ------------------------- ports/stm32/usbhost/Release_Notes.html | 973 ------------------------ 2 files changed, 1947 deletions(-) delete mode 100644 ports/stm32/usbdev/Release_Notes.html delete mode 100644 ports/stm32/usbhost/Release_Notes.html diff --git a/ports/stm32/usbdev/Release_Notes.html b/ports/stm32/usbdev/Release_Notes.html deleted file mode 100644 index 487b455266..0000000000 --- a/ports/stm32/usbdev/Release_Notes.html +++ /dev/null @@ -1,974 +0,0 @@ - - - - - - - - -Release Notes for STM32 USB Device Library - - - - - - - - -
- -

 

- -
- - - - - -
- - - - - - - -
-

Back to Release page

-
-

Release Notes for STM32 USB Device Library

-

Copyright - 2014 STMicroelectronics

-

-
-

 

- - - - -
-

Update History

-

V2.0.0 / 18-February-2014

- - - - - -

Main -Changes

- - - - - - - - - -
    -
  • Major update -based on STM32Cube specification: Library Core, Classes architecture and APIs -modified vs. V1.1.0, and thus the 2 versions are not compatible.
    -
  • This version has to be used only with STM32Cube based development
  • -
- - -

V1.1.0 / 19-March-2012

-

Main -Changes

- -
  • Official support of STM32F4xx devices
  • All source files: license disclaimer text update and add link to the License file on ST Internet.
  • Handle test mode in the set feature request
  • Handle dynamically the USB SELF POWERED feature
  • Handle correctly the USBD_CtlError process to take into account error during Control OUT stage
  • Miscellaneous bug fix

V1.0.0 / 22-July-2011

Main -Changes

-
  • First official version for STM32F105/7xx and STM32F2xx devices

-

License

-

Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); You may not use this package except in compliance with the License. You may obtain a copy of the License at:


Unless -required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT -WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See -the License for the specific language governing permissions and -limitations under the License.
-
-
-
-

For - complete documentation on STM32 - Microcontrollers visit www.st.com/STM32

-
-

-
- -
- -

 

- -
- - \ No newline at end of file diff --git a/ports/stm32/usbhost/Release_Notes.html b/ports/stm32/usbhost/Release_Notes.html deleted file mode 100644 index cbb723ee94..0000000000 --- a/ports/stm32/usbhost/Release_Notes.html +++ /dev/null @@ -1,973 +0,0 @@ - - - - - - - - -Release Notes for STM32 USB Host Library - - - - - - - - -
- -

 

- -
- - - - - -
- - - - - - - -
-

Back to Release page

-
-

Release Notes for STM32 USB Host Library

-

Copyright - 2014 STMicroelectronics

-

-
-

 

- - - - -
-

Update History

- -

V3.0.0 / 18-February-2014

- - - -

Main -Changes

- - - - - - - -
    -
  • Major update -based on STM32Cube specification: Library Core, Classes architecture and APIs -modified vs. V2.1.0, and thus the 2 versions are not compatible.
    -
  • -
  • This version has to be used only with STM32Cube based development
  • -
-

V2.1.0 / 19-March-2012

-

Main -Changes

- -
  • Official support of STM32F4xx devices
  • All source files: license disclaimer text update and add link to the License file on ST Internet
  • Add ISR structure to link the low level driver to the Host library
  • Change length parameter in the I/O operations to handle large amount of data
  • Enhance the configuration descriptor parsing method to take into account multi interface devices
  • HID class
    • Remove blocking even frame synchronization loop
  • MSC class
    • Handle correctly the BOT transfer with length < max length
    • Handle multi sector length data in the FAT FS interface
  • Miscellaneous bug fix

V2.0.0 / 22-July-2011

Main -Changes

-
  • Second official version supporting STM32F105/7 and STM32F2xx devices
  • Add support for STM32F2xx devices
  • Add multi interface feature
  • Add dynamic configuration parsing
  • Add -USBH_DeAllocate_AllChannel function in the Host channel management -layer to clean up channels allocation table when de-initializing the -library
  • Change the core layer to stop correctly the host core and free all allocated channels
  • Add usbh_conf.h file in the application layer to customize some user parameters

V1.0.0 - 11/29/2010

-
  • Created 

License

-

Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); You may not use this package except in compliance with the License. You may obtain a copy of the License at:


Unless -required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT -WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See -the License for the specific language governing permissions and -limitations under the License.
-
-
-
-

For - complete documentation on STM32 - Microcontrollers visit www.st.com/STM32

-
-

-
- -
- -

 

- -
- - \ No newline at end of file From f47eeab0ad4c71960f000b8445db41533716d4ad Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 24 May 2018 23:07:29 +1000 Subject: [PATCH 717/828] stm32: Add low-level hardware I2C slave driver. --- ports/stm32/i2cslave.c | 101 +++++++++++++++++++++++++++++++++++++++++ ports/stm32/i2cslave.h | 60 ++++++++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 ports/stm32/i2cslave.c create mode 100644 ports/stm32/i2cslave.h diff --git a/ports/stm32/i2cslave.c b/ports/stm32/i2cslave.c new file mode 100644 index 0000000000..f8ff19cd6c --- /dev/null +++ b/ports/stm32/i2cslave.c @@ -0,0 +1,101 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "i2cslave.h" + +#if defined(STM32F4) + +void i2c_slave_init_helper(i2c_slave_t *i2c, int addr) { + i2c->CR2 = I2C_CR2_ITBUFEN | I2C_CR2_ITEVTEN | 4 << I2C_CR2_FREQ_Pos; + i2c->OAR1 = 1 << 14 | addr << 1; + i2c->OAR2 = 0; + i2c->CR1 = I2C_CR1_ACK | I2C_CR1_PE; +} + +void i2c_slave_ev_irq_handler(i2c_slave_t *i2c) { + uint32_t sr1 = i2c->SR1; + if (sr1 & I2C_SR1_ADDR) { + // Address matched + // Read of SR1, SR2 needed to clear ADDR bit + sr1 = i2c->SR1; + uint32_t sr2 = i2c->SR2; + i2c_slave_process_addr_match((sr2 >> I2C_SR2_TRA_Pos) & 1); + } + if (sr1 & I2C_SR1_STOPF) { + // STOPF only set at end of RX mode (in TX mode AF is set on NACK) + // Read of SR1, write CR1 needed to clear STOPF bit + sr1 = i2c->SR1; + i2c->CR1 &= ~I2C_CR1_ACK; + i2c_slave_process_rx_end(); + i2c->CR1 |= I2C_CR1_ACK; + } + if (sr1 & I2C_SR1_TXE) { + i2c->DR = i2c_slave_process_tx_byte(); + } + if (sr1 & I2C_SR1_RXNE) { + i2c_slave_process_rx_byte(i2c->DR); + } +} + +#elif defined(STM32F7) + +void i2c_slave_init_helper(i2c_slave_t *i2c, int addr) { + i2c->CR1 = I2C_CR1_STOPIE | I2C_CR1_ADDRIE | I2C_CR1_RXIE | I2C_CR1_TXIE; + i2c->CR2 = 0; + i2c->OAR1 = I2C_OAR1_OA1EN | addr << 1; + i2c->OAR2 = 0; + i2c->CR1 |= I2C_CR1_PE; +} + +void i2c_slave_ev_irq_handler(i2c_slave_t *i2c) { + uint32_t isr = i2c->ISR; + if (isr & I2C_ISR_ADDR) { + // Address matched + // Set TXE so that TXDR is flushed and ready for the first byte + i2c->ISR = I2C_ISR_TXE; + i2c->ICR = I2C_ICR_ADDRCF; + i2c_slave_process_addr_match(0); + } + if (isr & I2C_ISR_STOPF) { + // STOPF only set for STOP condition, not a repeated START + i2c->ICR = I2C_ICR_STOPCF; + i2c->OAR1 &= ~I2C_OAR1_OA1EN; + if (i2c->ISR & I2C_ISR_DIR) { + //i2c_slave_process_tx_end(); + } else { + i2c_slave_process_rx_end(); + } + i2c->OAR1 |= I2C_OAR1_OA1EN; + } + if (isr & I2C_ISR_TXIS) { + i2c->TXDR = i2c_slave_process_tx_byte(); + } + if (isr & I2C_ISR_RXNE) { + i2c_slave_process_rx_byte(i2c->RXDR); + } +} + +#endif diff --git a/ports/stm32/i2cslave.h b/ports/stm32/i2cslave.h new file mode 100644 index 0000000000..ac35c0cc82 --- /dev/null +++ b/ports/stm32/i2cslave.h @@ -0,0 +1,60 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_I2CSLAVE_H +#define MICROPY_INCLUDED_STM32_I2CSLAVE_H + +#include STM32_HAL_H + +typedef I2C_TypeDef i2c_slave_t; + +void i2c_slave_init_helper(i2c_slave_t *i2c, int addr); + +static inline void i2c_slave_init(i2c_slave_t *i2c, int irqn, int irq_pri, int addr) { + int en_bit = RCC_APB1ENR_I2C1EN_Pos + ((uintptr_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); + RCC->APB1ENR |= 1 << en_bit; + volatile uint32_t tmp = RCC->APB1ENR; // Delay after enabling clock + (void)tmp; + + i2c_slave_init_helper(i2c, addr); + + NVIC_SetPriority(irqn, irq_pri); + NVIC_EnableIRQ(irqn); +} + +static inline void i2c_slave_shutdown(i2c_slave_t *i2c, int irqn) { + i2c->CR1 = 0; + NVIC_DisableIRQ(irqn); +} + +void i2c_slave_ev_irq_handler(i2c_slave_t *i2c); + +// These should be provided externally +int i2c_slave_process_addr_match(int rw); +int i2c_slave_process_rx_byte(uint8_t val); +void i2c_slave_process_rx_end(void); +uint8_t i2c_slave_process_tx_byte(void); + +#endif // MICROPY_INCLUDED_STM32_I2CSLAVE_H From 15ddc2043687942c68d9ab54176fd837f44d3083 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 24 May 2018 23:15:20 +1000 Subject: [PATCH 718/828] stm32: Add new component, the mboot bootloader. Mboot is a custom bootloader for STM32 MCUs. It can provide a USB DFU interface on either the FS or HS peripherals, as well as a custom I2C bootloader interface. --- ports/stm32/mboot/Makefile | 189 +++++ ports/stm32/mboot/README.md | 52 ++ ports/stm32/mboot/main.c | 1256 ++++++++++++++++++++++++++++ ports/stm32/mboot/mboot.py | 177 ++++ ports/stm32/mboot/mphalport.h | 155 ++++ ports/stm32/mboot/stm32_generic.ld | 77 ++ 6 files changed, 1906 insertions(+) create mode 100644 ports/stm32/mboot/Makefile create mode 100644 ports/stm32/mboot/README.md create mode 100644 ports/stm32/mboot/main.c create mode 100644 ports/stm32/mboot/mboot.py create mode 100644 ports/stm32/mboot/mphalport.h create mode 100644 ports/stm32/mboot/stm32_generic.ld diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile new file mode 100644 index 0000000000..b9f439482e --- /dev/null +++ b/ports/stm32/mboot/Makefile @@ -0,0 +1,189 @@ +# Select the board to build for: if not given on the command line, +# then default to PYBV10. +BOARD ?= PYBV10 +ifeq ($(wildcard ../boards/$(BOARD)/.),) +$(error Invalid BOARD specified) +endif + +# If the build directory is not given, make it reflect the board name. +BUILD ?= build-$(BOARD) + +include ../../../py/mkenv.mk +include ../boards/$(BOARD)/mpconfigboard.mk + +CMSIS_DIR=$(TOP)/lib/stm32lib/CMSIS/STM32$(MCU_SERIES_UPPER)xx/Include +MCU_SERIES_UPPER = $(shell echo $(MCU_SERIES) | tr '[:lower:]' '[:upper:]') +HAL_DIR=lib/stm32lib/STM32$(MCU_SERIES_UPPER)xx_HAL_Driver +USBDEV_DIR=usbdev +DFU=$(TOP)/tools/dfu.py +PYDFU ?= $(TOP)/tools/pydfu.py +DEVICE=0483:df11 +STFLASH ?= st-flash +OPENOCD ?= openocd +OPENOCD_CONFIG ?= boards/openocd_stm32f4.cfg + +CROSS_COMPILE = arm-none-eabi- + +INC += -I. +INC += -I.. +INC += -I$(TOP) +INC += -I$(BUILD) +INC += -I$(TOP)/lib/cmsis/inc +INC += -I$(CMSIS_DIR)/ +INC += -I$(TOP)/$(HAL_DIR)/Inc +INC += -I../$(USBDEV_DIR)/core/inc -I../$(USBDEV_DIR)/class/inc + +# Basic Cortex-M flags +CFLAGS_CORTEX_M = -mthumb + +# Options for particular MCU series +CFLAGS_MCU_f4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 +CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 +CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 + +CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_EXTRA) +CFLAGS += -D$(CMSIS_MCU) +CFLAGS += $(CFLAGS_MCU_$(MCU_SERIES)) +CFLAGS += $(COPT) +CFLAGS += -I../boards/$(BOARD) +CFLAGS += -DSTM32_HAL_H='' +CFLAGS += -DBOARD_$(BOARD) +CFLAGS += -DAPPLICATION_ADDR=$(TEXT0_ADDR) + +LDFLAGS = -nostdlib -L . -T stm32_generic.ld -Map=$(@:.elf=.map) --cref +LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) + +# Remove uncalled code from the final image. +CFLAGS += -fdata-sections -ffunction-sections +LDFLAGS += --gc-sections + +# Debugging/Optimization +ifeq ($(DEBUG), 1) +CFLAGS += -g -DPENDSV_DEBUG +COPT = -O0 +else +COPT += -Os -DNDEBUG +endif + +SRC_LIB = $(addprefix lib/,\ + libc/string0.c \ + ) + +SRC_C = \ + main.c \ + drivers/bus/softspi.c \ + drivers/bus/softqspi.c \ + drivers/memory/spiflash.c \ + ports/stm32/i2cslave.c \ + ports/stm32/qspi.c \ + ports/stm32/flashbdev.c \ + ports/stm32/spibdev.c \ + ports/stm32/usbd_conf.c \ + $(patsubst $(TOP)/%,%,$(wildcard $(TOP)/ports/stm32/boards/$(BOARD)/*.c)) + +SRC_O = \ + ports/stm32/boards/startup_stm32$(MCU_SERIES).o \ + ports/stm32/resethandler.o \ + +SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ + hal_cortex.c \ + hal_flash.c \ + hal_flash_ex.c \ + hal_pcd.c \ + hal_pcd_ex.c \ + ll_usb.c \ + ) + +SRC_USBDEV = $(addprefix ports/stm32/$(USBDEV_DIR)/,\ + core/src/usbd_core.c \ + core/src/usbd_ctlreq.c \ + core/src/usbd_ioreq.c \ + ) + +OBJ = +OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_O)) +OBJ += $(addprefix $(BUILD)/, $(SRC_HAL:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_USBDEV:.c=.o)) + +all: $(TOP)/lib/stm32lib/README.md $(BUILD)/firmware.dfu $(BUILD)/firmware.hex + +# For convenience, automatically fetch required submodules if they don't exist +$(TOP)/lib/stm32lib/README.md: + $(ECHO) "stm32lib submodule not found, fetching it now..." + (cd $(TOP) && git submodule update --init lib/stm32lib) + +.PHONY: deploy + +deploy: $(BUILD)/firmware.dfu + $(ECHO) "Writing $< to the board" + $(Q)$(PYTHON) $(PYDFU) -u $< + +FLASH_ADDR = 0x08000000 + +$(BUILD)/firmware.dfu: $(BUILD)/firmware.elf + $(ECHO) "Create $@" + $(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data $^ $(BUILD)/firmware.bin + $(Q)$(PYTHON) $(DFU) -b $(FLASH_ADDR):$(BUILD)/firmware.bin $@ + +$(BUILD)/firmware.hex: $(BUILD)/firmware.elf + $(ECHO) "Create $@" + $(Q)$(OBJCOPY) -O ihex $< $@ + +$(BUILD)/firmware.elf: $(OBJ) + $(ECHO) "LINK $@" + $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) + $(Q)$(SIZE) $@ + +######################################### + +vpath %.S . $(TOP) +$(BUILD)/%.o: %.S + $(ECHO) "CC $<" + $(Q)$(CC) $(CFLAGS) -c -o $@ $< + +vpath %.s . $(TOP) +$(BUILD)/%.o: %.s + $(ECHO) "AS $<" + $(Q)$(AS) -o $@ $< + +define compile_c +$(ECHO) "CC $<" +$(Q)$(CC) $(CFLAGS) -c -MD -o $@ $< +@# The following fixes the dependency file. +@# See http://make.paulandlesley.org/autodep.html for details. +@# Regex adjusted from the above to play better with Windows paths, etc. +@$(CP) $(@:.o=.d) $(@:.o=.P); \ + $(SED) -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \ + $(RM) -f $(@:.o=.d) +endef + +vpath %.c . $(TOP) +$(BUILD)/%.o: %.c + $(call compile_c) + +# $(sort $(var)) removes duplicates +# +# The net effect of this, is it causes the objects to depend on the +# object directories (but only for existence), and the object directories +# will be created if they don't exist. +OBJ_DIRS = $(sort $(dir $(OBJ))) +$(OBJ): | $(OBJ_DIRS) +$(OBJ_DIRS): + $(MKDIR) -p $@ + +clean: + $(RM) -rf $(BUILD) $(CLEAN_EXTRA) +.PHONY: clean + +########################################### + +$(BUILD)/main.o: $(BUILD)/genhdr/qstrdefs.generated.h + +$(BUILD)/genhdr/qstrdefs.generated.h: + $(MKDIR) -p $(BUILD)/genhdr + $(Q)echo "// empty" > $@ + +-include $(OBJ:.o=.P) diff --git a/ports/stm32/mboot/README.md b/ports/stm32/mboot/README.md new file mode 100644 index 0000000000..3486ebfb33 --- /dev/null +++ b/ports/stm32/mboot/README.md @@ -0,0 +1,52 @@ +Mboot - MicroPython boot loader +=============================== + +Mboot is a custom bootloader for STM32 MCUs, and currently supports the +STM32F4xx and STM32F7xx families. It can provide a standard USB DFU interface +on either the FS or HS peripherals, as well as a sophisticated, custom I2C +interface. It fits in 16k of flash space. + +How to use +---------- + +1. Configure your board to use a boot loader by editing the mpconfigboard.mk + and mpconfigboard.h files. For example, for an F767 be sure to have these + lines in mpconfigboard.mk: + + LD_FILES = boards/stm32f767.ld boards/common_bl.ld + TEXT0_ADDR = 0x08008000 + + And this in mpconfigboard.h (recommended to put at the end of the file): + + // Bootloader configuration + #define MBOOT_I2C_PERIPH_ID 1 + #define MBOOT_I2C_SCL (pin_B8) + #define MBOOT_I2C_SDA (pin_B9) + #define MBOOT_I2C_ALTFUNC (4) + + To configure a pin to force entry into the boot loader the following + options can be used (with example configuration): + + #define MBOOT_BOOTPIN_PIN (pin_A0) + #define MBOOT_BOOTPIN_PULL (MP_HAL_PIN_PULL_UP) + #define MBOOT_BOOTPIN_ACTIVE (0) + +2. Build the board's main application firmware as usual. + +3. Build mboot via: + + $ cd mboot + $ make BOARD= + + That should produce a DFU file for mboot. It can be deployed using + USB DFU programming via (it will be placed at location 0x08000000): + + $ make BOARD= deploy + +4. Reset the board while holding USR until all 3 LEDs are lit (the 4th option in + the cycle) and then release USR. LED0 will then blink once per second to + indicate that it's in mboot + +5. Use either USB DFU or I2C to download firmware. The script mboot.py shows how + to communicate with the I2C boot loader interface. It should be run on a + pyboard connected via I2C to the target board. diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c new file mode 100644 index 0000000000..b602f19964 --- /dev/null +++ b/ports/stm32/mboot/main.c @@ -0,0 +1,1256 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/mphal.h" +#include "extmod/crypto-algorithms/sha256.c" +#include "usbd_core.h" +#include "storage.h" +#include "i2cslave.h" + +// Using polling is about 10% faster than not using it (and using IRQ instead) +// This DFU code with polling runs in about 70% of the time of the ST bootloader +#define USE_USB_POLLING (1) + +// Using cache probably won't make it faster because we run at 48MHz, and best +// to keep the MCU config as minimal as possible. +#define USE_CACHE (0) + +// IRQ priorities (encoded values suitable for NVIC_SetPriority) +#define IRQ_PRI_SYSTICK (NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 0, 0)) +#define IRQ_PRI_I2C (NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 1, 0)) + +// Configure PLL to give a 48MHz CPU freq +#define CORE_PLL_FREQ (48000000) +#undef MICROPY_HW_CLK_PLLM +#undef MICROPY_HW_CLK_PLLN +#undef MICROPY_HW_CLK_PLLP +#undef MICROPY_HW_CLK_PLLQ +#define MICROPY_HW_CLK_PLLM (HSE_VALUE / 1000000) +#define MICROPY_HW_CLK_PLLN (192) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV4) +#define MICROPY_HW_CLK_PLLQ (4) + +// Work out which USB device to use for the USB DFU interface +#if !defined(MICROPY_HW_USB_MAIN_DEV) +#if defined(MICROPY_HW_USB_FS) +#define MICROPY_HW_USB_MAIN_DEV (USB_PHY_FS_ID) +#elif defined(MICROPY_HW_USB_HS) && defined(MICROPY_HW_USB_HS_IN_FS) +#define MICROPY_HW_USB_MAIN_DEV (USB_PHY_HS_ID) +#else +#error Unable to determine proper MICROPY_HW_USB_MAIN_DEV to use +#endif +#endif + +// These bits are used to detect valid application firmware at APPLICATION_ADDR +#define APP_VALIDITY_BITS (0x00000003) + +#define MP_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +static void do_reset(void); + +static uint32_t get_le32(const uint8_t *b) { + return b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24; +} + +void mp_hal_delay_us(mp_uint_t usec) { + // use a busy loop for the delay + // sys freq is always a multiple of 2MHz, so division here won't lose precision + const uint32_t ucount = HAL_RCC_GetSysClockFreq() / 2000000 * usec / 2; + for (uint32_t count = 0; ++count <= ucount;) { + } +} + +static volatile uint32_t systick_ms; + +void mp_hal_delay_ms(mp_uint_t ms) { + if (__get_PRIMASK() == 0) { + // IRQs enabled, use systick + if (ms != 0 && ms != (mp_uint_t)-1) { + ++ms; // account for the fact that systick_ms may roll over immediately + } + uint32_t start = systick_ms; + while (systick_ms - start < ms) { + __WFI(); + } + } else { + // IRQs disabled, so need to use a busy loop for the delay. + // To prevent possible overflow of the counter we use a double loop. + const uint32_t count_1ms = 16000000 / 8000; + for (uint32_t i = 0; i < ms; i++) { + for (volatile uint32_t count = 0; ++count <= count_1ms;) { + } + } + } +} + +// Needed by parts of the HAL +uint32_t HAL_GetTick(void) { + return systick_ms; +} + +// Needed by parts of the HAL +void HAL_Delay(uint32_t ms) { + mp_hal_delay_ms(ms); +} + +static void __fatal_error(const char *msg) { + NVIC_SystemReset(); + for (;;) { + } +} + +/******************************************************************************/ +// CLOCK + +#if defined(STM32F4) || defined(STM32F7) + +#define CONFIG_RCC_CR_1ST (RCC_CR_HSION) +#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON || RCC_CR_CSSON || RCC_CR_PLLON) +#define CONFIG_RCC_PLLCFGR (0x24003010) + +#else +#error Unknown processor +#endif + +void SystemInit(void) { + // Set HSION bit + RCC->CR |= CONFIG_RCC_CR_1ST; + + // Reset CFGR register + RCC->CFGR = 0x00000000; + + // Reset HSEON, CSSON and PLLON bits + RCC->CR &= ~CONFIG_RCC_CR_2ND; + + // Reset PLLCFGR register + RCC->PLLCFGR = CONFIG_RCC_PLLCFGR; + + // Reset HSEBYP bit + RCC->CR &= (uint32_t)0xFFFBFFFF; + + // Disable all interrupts + RCC->CIR = 0x00000000; + + // Set location of vector table + SCB->VTOR = FLASH_BASE; + + // Enable 8-byte stack alignment for IRQ handlers, in accord with EABI + SCB->CCR |= SCB_CCR_STKALIGN_Msk; +} + +void systick_init(void) { + // Configure SysTick as 1ms ticker + SysTick_Config(SystemCoreClock / 1000); + NVIC_SetPriority(SysTick_IRQn, IRQ_PRI_SYSTICK); +} + +void SystemClock_Config(void) { + // This function assumes that HSI is used as the system clock (see RCC->CFGR, SWS bits) + + // Enable Power Control clock + __HAL_RCC_PWR_CLK_ENABLE(); + + // Reduce power consumption + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + + // Turn HSE on + __HAL_RCC_HSE_CONFIG(RCC_HSE_ON); + while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET) { + } + + // Disable PLL + __HAL_RCC_PLL_DISABLE(); + while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) != RESET) { + } + + // Configure PLL factors and source + RCC->PLLCFGR = + 1 << RCC_PLLCFGR_PLLSRC_Pos // HSE selected as PLL source + | MICROPY_HW_CLK_PLLM << RCC_PLLCFGR_PLLM_Pos + | MICROPY_HW_CLK_PLLN << RCC_PLLCFGR_PLLN_Pos + | ((MICROPY_HW_CLK_PLLP >> 1) - 1) << RCC_PLLCFGR_PLLP_Pos + | MICROPY_HW_CLK_PLLQ << RCC_PLLCFGR_PLLQ_Pos + #ifdef RCC_PLLCFGR_PLLR + | 2 << RCC_PLLCFGR_PLLR_Pos // default PLLR value of 2 + #endif + ; + + // Enable PLL + __HAL_RCC_PLL_ENABLE(); + while(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET) { + } + + #if !defined(MICROPY_HW_FLASH_LATENCY) + #define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_1 + #endif + + // Increase latency before changing clock + if (MICROPY_HW_FLASH_LATENCY > (FLASH->ACR & FLASH_ACR_LATENCY)) { + __HAL_FLASH_SET_LATENCY(MICROPY_HW_FLASH_LATENCY); + } + + // Configure AHB divider + MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_SYSCLK_DIV1); + + // Configure SYSCLK source from PLL + __HAL_RCC_SYSCLK_CONFIG(RCC_SYSCLKSOURCE_PLLCLK); + while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_SYSCLKSOURCE_STATUS_PLLCLK) { + } + + // Decrease latency after changing clock + if (MICROPY_HW_FLASH_LATENCY < (FLASH->ACR & FLASH_ACR_LATENCY)) { + __HAL_FLASH_SET_LATENCY(MICROPY_HW_FLASH_LATENCY); + } + + // Set APB clock dividers + MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_HCLK_DIV4); + MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, RCC_HCLK_DIV2 << 3); + + // Update clock value and reconfigure systick now that the frequency changed + SystemCoreClock = CORE_PLL_FREQ; + systick_init(); + + #if defined(STM32F7) + // The DFU bootloader changes the clocksource register from its default power + // on reset value, so we set it back here, so the clocksources are the same + // whether we were started from DFU or from a power on reset. + RCC->DCKCFGR2 = 0; + #endif +} + +// Needed by HAL_PCD_IRQHandler +uint32_t HAL_RCC_GetHCLKFreq(void) { + return SystemCoreClock; +} + +/******************************************************************************/ +// GPIO + +void mp_hal_pin_config(mp_hal_pin_obj_t port_pin, uint32_t mode, uint32_t pull, uint32_t alt) { + GPIO_TypeDef *gpio = (GPIO_TypeDef*)(port_pin & ~0xf); + + // Enable the GPIO peripheral clock + uint32_t en_bit = RCC_AHB1ENR_GPIOAEN_Pos + ((uintptr_t)gpio - GPIOA_BASE) / (GPIOB_BASE - GPIOA_BASE); + RCC->AHB1ENR |= 1 << en_bit; + volatile uint32_t tmp = RCC->AHB1ENR; // Delay after enabling clock + (void)tmp; + + // Configure the pin + uint32_t pin = port_pin & 0xf; + gpio->MODER = (gpio->MODER & ~(3 << (2 * pin))) | ((mode & 3) << (2 * pin)); + gpio->OTYPER = (gpio->OTYPER & ~(1 << pin)) | ((mode >> 2) << pin); + gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << (2 * pin))) | (2 << (2 * pin)); // full speed + gpio->PUPDR = (gpio->PUPDR & ~(3 << (2 * pin))) | (pull << (2 * pin)); + gpio->AFR[pin >> 3] = (gpio->AFR[pin >> 3] & ~(15 << (4 * (pin & 7)))) | (alt << (4 * (pin & 7))); +} + +void mp_hal_pin_config_speed(uint32_t port_pin, uint32_t speed) { + GPIO_TypeDef *gpio = (GPIO_TypeDef*)(port_pin & ~0xf); + uint32_t pin = port_pin & 0xf; + gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << (2 * pin))) | (speed << (2 * pin)); +} + +/******************************************************************************/ +// LED + +#define LED0 MICROPY_HW_LED1 +#define LED1 MICROPY_HW_LED2 +#define LED2 MICROPY_HW_LED3 + +void led_init(void) { + mp_hal_pin_output(LED0); + mp_hal_pin_output(LED1); + mp_hal_pin_output(LED2); +} + +void led_state(int led, int val) { + if (led == 1) { + led = LED0; + } + if (val) { + MICROPY_HW_LED_ON(led); + } else { + MICROPY_HW_LED_OFF(led); + } +} + +/******************************************************************************/ +// USR BUTTON + +static void usrbtn_init(void) { + mp_hal_pin_config(MICROPY_HW_USRSW_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_USRSW_PULL, 0); +} + +static int usrbtn_state(void) { + return mp_hal_pin_read(MICROPY_HW_USRSW_PIN) == MICROPY_HW_USRSW_PRESSED; +} + +/******************************************************************************/ +// FLASH + +typedef struct { + uint32_t base_address; + uint32_t sector_size; + uint32_t sector_count; +} flash_layout_t; + +#if defined(STM32F7) +// FLASH_FLAG_PGSERR (Programming Sequence Error) was renamed to +// FLASH_FLAG_ERSERR (Erasing Sequence Error) in STM32F7 +#define FLASH_FLAG_PGSERR FLASH_FLAG_ERSERR +#endif + +#if defined(STM32F4) \ + || defined(STM32F722xx) \ + || defined(STM32F723xx) \ + || defined(STM32F732xx) \ + || defined(STM32F733xx) + +#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg" + +static const flash_layout_t flash_layout[] = { + { 0x08000000, 0x04000, 4 }, + { 0x08010000, 0x10000, 1 }, + { 0x08020000, 0x20000, 3 }, + #if defined(FLASH_SECTOR_8) + { 0x08080000, 0x20000, 4 }, + #endif + #if defined(FLASH_SECTOR_12) + { 0x08100000, 0x04000, 4 }, + { 0x08110000, 0x10000, 1 }, + { 0x08120000, 0x20000, 7 }, + #endif +}; + +#elif defined(STM32F767xx) + +#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*032Kg,01*128Kg,07*256Kg" + +// This is for dual-bank mode disabled +static const flash_layout_t flash_layout[] = { + { 0x08000000, 0x08000, 4 }, + { 0x08020000, 0x20000, 1 }, + { 0x08040000, 0x40000, 7 }, +}; + +#endif + +static uint32_t flash_get_sector_index(uint32_t addr) { + if (addr >= flash_layout[0].base_address) { + uint32_t sector_index = 0; + for (int i = 0; i < MP_ARRAY_SIZE(flash_layout); ++i) { + for (int j = 0; j < flash_layout[i].sector_count; ++j) { + uint32_t sector_start_next = flash_layout[i].base_address + + (j + 1) * flash_layout[i].sector_size; + if (addr < sector_start_next) { + return sector_index; + } + ++sector_index; + } + } + } + return 0; +} + +static int do_mass_erase(void) { + // TODO + return -1; +} + +static int do_page_erase(uint32_t addr) { + uint32_t sector = flash_get_sector_index(addr); + if (sector == 0) { + // Don't allow to erase the sector with this bootloader in it + return -1; + } + + led_state(LED0, 1); + + HAL_FLASH_Unlock(); + + // Clear pending flags (if any) + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | + FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); + + // erase the sector(s) + FLASH_EraseInitTypeDef EraseInitStruct; + EraseInitStruct.TypeErase = TYPEERASE_SECTORS; + EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V + EraseInitStruct.Sector = sector; + EraseInitStruct.NbSectors = 1; + + uint32_t SectorError = 0; + if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) { + // error occurred during sector erase + return -1; + } + + led_state(LED0, 0); + + // Check the erase set bits to 1, at least for the first 256 bytes + for (int i = 0; i < 64; ++i) { + if (((volatile uint32_t*)addr)[i] != 0xffffffff) { + return -2; + } + } + + return 0; +} + +static int do_write(uint32_t addr, const uint8_t *src8, size_t len) { + if (addr >= flash_layout[0].base_address && addr < flash_layout[0].base_address + flash_layout[0].sector_size) { + // Don't allow to write the sector with this bootloader in it + return -1; + } + + static uint32_t led_tog = 0; + led_state(LED0, (led_tog++) & 16); + + const uint32_t *src = (const uint32_t*)src8; + size_t num_word32 = (len + 3) / 4; + HAL_FLASH_Unlock(); + // program the flash word by word + for (size_t i = 0; i < num_word32; i++) { + if (HAL_FLASH_Program(TYPEPROGRAM_WORD, addr, *src) != HAL_OK) { + return -1; + } + addr += 4; + src += 1; + } + + // TODO verify data + + return 0; +} + +/******************************************************************************/ +// I2C slave interface + +#if defined(MBOOT_I2C_SCL) + +#define PASTE2(a, b) a ## b +#define PASTE3(a, b, c) a ## b ## c +#define EVAL_PASTE2(a, b) PASTE2(a, b) +#define EVAL_PASTE3(a, b, c) PASTE3(a, b, c) + +#define MBOOT_I2Cx EVAL_PASTE2(I2C, MBOOT_I2C_PERIPH_ID) +#define I2Cx_EV_IRQn EVAL_PASTE3(I2C, MBOOT_I2C_PERIPH_ID, _EV_IRQn) +#define I2Cx_EV_IRQHandler EVAL_PASTE3(I2C, MBOOT_I2C_PERIPH_ID, _EV_IRQHandler) + +#define I2C_CMD_BUF_LEN (129) + +enum { + I2C_CMD_ECHO = 1, + I2C_CMD_GETID, // () -> u8*12 unique id, ASCIIZ mcu name, ASCIIZ board name + I2C_CMD_GETCAPS, // not implemented + I2C_CMD_RESET, // () -> () + I2C_CMD_CONFIG, // not implemented + I2C_CMD_GETLAYOUT, // () -> ASCII string + I2C_CMD_MASSERASE, // () -> () + I2C_CMD_PAGEERASE, // le32 -> () + I2C_CMD_SETRDADDR, // le32 -> () + I2C_CMD_SETWRADDR, // le32 -> () + I2C_CMD_READ, // u8 -> bytes + I2C_CMD_WRITE, // bytes -> () + I2C_CMD_COPY, // not implemented + I2C_CMD_CALCHASH, // le32 -> u8*32 + I2C_CMD_MARKVALID, // () -> () +}; + +typedef struct _i2c_obj_t { + volatile bool cmd_send_arg; + volatile bool cmd_arg_sent; + volatile int cmd_arg; + volatile uint32_t cmd_rdaddr; + volatile uint32_t cmd_wraddr; + volatile uint16_t cmd_buf_pos; + uint8_t cmd_buf[I2C_CMD_BUF_LEN]; +} i2c_obj_t; + +static i2c_obj_t i2c_obj; + +void i2c_init(int addr) { + i2c_obj.cmd_send_arg = false; + + mp_hal_pin_config(MBOOT_I2C_SCL, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_NONE, MBOOT_I2C_ALTFUNC); + mp_hal_pin_config(MBOOT_I2C_SDA, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_NONE, MBOOT_I2C_ALTFUNC); + + i2c_slave_init(MBOOT_I2Cx, I2Cx_EV_IRQn, IRQ_PRI_I2C, addr); +} + +int i2c_slave_process_addr_match(int rw) { + if (i2c_obj.cmd_arg_sent) { + i2c_obj.cmd_send_arg = false; + } + i2c_obj.cmd_buf_pos = 0; + return 0; // ACK +} + +int i2c_slave_process_rx_byte(uint8_t val) { + if (i2c_obj.cmd_buf_pos < sizeof(i2c_obj.cmd_buf)) { + i2c_obj.cmd_buf[i2c_obj.cmd_buf_pos++] = val; + } + return 0; // ACK +} + +void i2c_slave_process_rx_end(void) { + if (i2c_obj.cmd_buf_pos == 0) { + return; + } + + int len = i2c_obj.cmd_buf_pos - 1; + uint8_t *buf = i2c_obj.cmd_buf; + + if (buf[0] == I2C_CMD_ECHO) { + ++len; + } else if (buf[0] == I2C_CMD_GETID && len == 0) { + memcpy(buf, (uint8_t*)MP_HAL_UNIQUE_ID_ADDRESS, 12); + memcpy(buf + 12, MICROPY_HW_MCU_NAME, sizeof(MICROPY_HW_MCU_NAME)); + memcpy(buf + 12 + sizeof(MICROPY_HW_MCU_NAME), MICROPY_HW_BOARD_NAME, sizeof(MICROPY_HW_BOARD_NAME) - 1); + len = 12 + sizeof(MICROPY_HW_MCU_NAME) + sizeof(MICROPY_HW_BOARD_NAME) - 1; + } else if (buf[0] == I2C_CMD_RESET && len == 0) { + do_reset(); + } else if (buf[0] == I2C_CMD_GETLAYOUT && len == 0) { + len = strlen(FLASH_LAYOUT_STR); + memcpy(buf, FLASH_LAYOUT_STR, len); + } else if (buf[0] == I2C_CMD_MASSERASE && len == 0) { + len = do_mass_erase(); + } else if (buf[0] == I2C_CMD_PAGEERASE && len == 4) { + len = do_page_erase(get_le32(buf + 1)); + } else if (buf[0] == I2C_CMD_SETRDADDR && len == 4) { + i2c_obj.cmd_rdaddr = get_le32(buf + 1); + len = 0; + } else if (buf[0] == I2C_CMD_SETWRADDR && len == 4) { + i2c_obj.cmd_wraddr = get_le32(buf + 1); + len = 0; + } else if (buf[0] == I2C_CMD_READ && len == 1) { + len = buf[1]; + if (len > I2C_CMD_BUF_LEN) { + len = I2C_CMD_BUF_LEN; + } + memcpy(buf, (void*)i2c_obj.cmd_rdaddr, len); + i2c_obj.cmd_rdaddr += len; + } else if (buf[0] == I2C_CMD_WRITE) { + if (i2c_obj.cmd_wraddr == APPLICATION_ADDR) { + // Mark the 2 lower bits to indicate invalid app firmware + buf[1] |= APP_VALIDITY_BITS; + } + int ret = do_write(i2c_obj.cmd_wraddr, buf + 1, len); + if (ret < 0) { + len = ret; + } else { + i2c_obj.cmd_wraddr += len; + len = 0; + } + } else if (buf[0] == I2C_CMD_CALCHASH && len == 4) { + uint32_t hashlen = get_le32(buf + 1); + static CRYAL_SHA256_CTX ctx; + sha256_init(&ctx); + sha256_update(&ctx, (const void*)i2c_obj.cmd_rdaddr, hashlen); + i2c_obj.cmd_rdaddr += hashlen; + sha256_final(&ctx, buf); + len = 32; + } else if (buf[0] == I2C_CMD_MARKVALID && len == 0) { + uint32_t buf; + buf = *(volatile uint32_t*)APPLICATION_ADDR; + if ((buf & APP_VALIDITY_BITS) != APP_VALIDITY_BITS) { + len = -1; + } else { + buf &= ~APP_VALIDITY_BITS; + int ret = do_write(APPLICATION_ADDR, (void*)&buf, 4); + if (ret < 0) { + len = ret; + } else { + buf = *(volatile uint32_t*)APPLICATION_ADDR; + if ((buf & APP_VALIDITY_BITS) != 0) { + len = -2; + } else { + len = 0; + } + } + } + } else { + len = -127; + } + i2c_obj.cmd_arg = len; + i2c_obj.cmd_send_arg = true; + i2c_obj.cmd_arg_sent = false; +} + +uint8_t i2c_slave_process_tx_byte(void) { + if (i2c_obj.cmd_send_arg) { + i2c_obj.cmd_arg_sent = true; + return i2c_obj.cmd_arg; + } else if (i2c_obj.cmd_buf_pos < sizeof(i2c_obj.cmd_buf)) { + return i2c_obj.cmd_buf[i2c_obj.cmd_buf_pos++]; + } else { + return 0; + } +} + +#endif // defined(MBOOT_I2C_SCL) + +/******************************************************************************/ +// DFU + +enum { + DFU_DNLOAD = 1, + DFU_UPLOAD = 2, + DFU_GETSTATUS = 3, + DFU_CLRSTATUS = 4, + DFU_ABORT = 6, +}; + +enum { + DFU_STATUS_IDLE = 2, + DFU_STATUS_BUSY = 4, + DFU_STATUS_DNLOAD_IDLE = 5, + DFU_STATUS_MANIFEST = 7, + DFU_STATUS_UPLOAD_IDLE = 9, + DFU_STATUS_ERROR = 0xa, +}; + +enum { + DFU_CMD_NONE = 0, + DFU_CMD_EXIT = 1, + DFU_CMD_UPLOAD = 7, + DFU_CMD_DNLOAD = 8, +}; + +typedef struct _dfu_state_t { + int status; + int cmd; + uint16_t wBlockNum; + uint16_t wLength; + uint32_t addr; + uint8_t buf[64] __attribute__((aligned(4))); +} dfu_state_t; + +static dfu_state_t dfu_state; + +static void dfu_init(void) { + dfu_state.status = DFU_STATUS_IDLE; + dfu_state.cmd = DFU_CMD_NONE; + dfu_state.addr = 0x08000000; +} + +static int dfu_process_dnload(void) { + int ret = -1; + if (dfu_state.wBlockNum == 0) { + // download control commands + if (dfu_state.wLength >= 1 && dfu_state.buf[0] == 0x41) { + if (dfu_state.wLength == 1) { + // mass erase + ret = do_mass_erase(); + } else if (dfu_state.wLength == 5) { + // erase page + ret = do_page_erase(get_le32(&dfu_state.buf[1])); + } + } else if (dfu_state.wLength >= 1 && dfu_state.buf[0] == 0x21) { + if (dfu_state.wLength == 5) { + // set address + dfu_state.addr = get_le32(&dfu_state.buf[1]); + ret = 0; + } + } + } else if (dfu_state.wBlockNum > 1) { + // write data to memory + ret = do_write(dfu_state.addr, dfu_state.buf, dfu_state.wLength); + } + if (ret == 0) { + return DFU_STATUS_DNLOAD_IDLE; + } else { + return DFU_STATUS_ERROR; + } +} + +static void dfu_handle_rx(int cmd, int arg, int len, const void *buf) { + if (cmd == DFU_CLRSTATUS) { + // clear status + dfu_state.status = DFU_STATUS_IDLE; + dfu_state.cmd = DFU_CMD_NONE; + } else if (cmd == DFU_ABORT) { + // clear status + dfu_state.status = DFU_STATUS_IDLE; + dfu_state.cmd = DFU_CMD_NONE; + } else if (cmd == DFU_DNLOAD) { + if (len == 0) { + // exit DFU + dfu_state.cmd = DFU_CMD_EXIT; + } else { + // download + dfu_state.cmd = DFU_CMD_DNLOAD; + dfu_state.wBlockNum = arg; + dfu_state.wLength = len; + memcpy(dfu_state.buf, buf, len); + } + } +} + +static void dfu_process(void) { + if (dfu_state.status == DFU_STATUS_MANIFEST) { + do_reset(); + } + + if (dfu_state.status == DFU_STATUS_BUSY) { + if (dfu_state.cmd == DFU_CMD_DNLOAD) { + dfu_state.cmd = DFU_CMD_NONE; + dfu_state.status = dfu_process_dnload(); + } + } +} + +static int dfu_handle_tx(int cmd, int arg, int len, uint8_t *buf, int max_len) { + if (cmd == DFU_UPLOAD) { + if (arg >= 2) { + dfu_state.cmd = DFU_CMD_UPLOAD; + memcpy(buf, (void*)((arg - 2) * max_len + dfu_state.addr), len); + return len; + } + } else if (cmd == DFU_GETSTATUS && len == 6) { + // execute command and get status + switch (dfu_state.cmd) { + case DFU_CMD_NONE: + break; + case DFU_CMD_EXIT: + dfu_state.status = DFU_STATUS_MANIFEST; + break; + case DFU_CMD_UPLOAD: + dfu_state.status = DFU_STATUS_UPLOAD_IDLE; + break; + case DFU_CMD_DNLOAD: + dfu_state.status = DFU_STATUS_BUSY; + break; + } + buf[0] = 0; + buf[1] = dfu_state.cmd; // TODO is this correct? + buf[2] = 0; + buf[3] = 0; + buf[4] = dfu_state.status; + buf[5] = 0; + return 6; + } + return -1; +} + +/******************************************************************************/ +// USB + +#define USB_TX_LEN (2048) + +enum { + USB_PHY_FS_ID = 0, + USB_PHY_HS_ID = 1, +}; + +typedef struct _pyb_usbdd_obj_t { + bool started; + USBD_HandleTypeDef hUSBDDevice; + + uint8_t bRequest; + uint16_t wValue; + uint16_t wLength; + uint8_t rx_buf[64]; + uint8_t tx_buf[USB_TX_LEN]; + bool tx_pending; + + // RAM to hold the current descriptors, which we configure on the fly + __ALIGN_BEGIN uint8_t usbd_device_desc[USB_LEN_DEV_DESC] __ALIGN_END; + __ALIGN_BEGIN uint8_t usbd_str_desc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END; +} pyb_usbdd_obj_t; + +#define USBD_LANGID_STRING (0x409) + +__ALIGN_BEGIN static const uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = { + USB_LEN_LANGID_STR_DESC, + USB_DESC_TYPE_STRING, + LOBYTE(USBD_LANGID_STRING), + HIBYTE(USBD_LANGID_STRING), +}; + +static const uint8_t dev_descr[0x12] = "\x12\x01\x00\x01\x00\x00\x00\x40\x83\x04\x11\xdf\x00\x22\x01\x02\x03\x01"; + +// This may be modified by USBD_GetDescriptor +static uint8_t cfg_descr[9 + 9 + 9] = + "\x09\x02\x1b\x00\x01\x01\x00\xc0\x32" + "\x09\x04\x00\x00\x00\xfe\x01\x02\x04" + "\x09\x21\x0b\xff\x00\x00\x08\x1a\x01" // \x00\x08 goes with tx_buf[USB_TX_LEN] +; + +static uint8_t *pyb_usbdd_DeviceDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { + *length = USB_LEN_DEV_DESC; + return (uint8_t*)dev_descr; +} + +static char get_hex_char(int val) { + val &= 0xf; + if (val <= 9) { + return '0' + val; + } else { + return 'A' + val - 10; + } +} + +static void format_hex(char *buf, int val) { + buf[0] = get_hex_char(val >> 4); + buf[1] = get_hex_char(val); +} + +static uint8_t *pyb_usbdd_StrDescriptor(USBD_HandleTypeDef *pdev, uint8_t idx, uint16_t *length) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + uint8_t *str_desc = self->usbd_str_desc; + switch (idx) { + case USBD_IDX_LANGID_STR: + *length = sizeof(USBD_LangIDDesc); + return (uint8_t*)USBD_LangIDDesc; // the data should only be read from this buf + + case USBD_IDX_MFC_STR: + USBD_GetString((uint8_t*)"USBDevice Manuf", str_desc, length); + return str_desc; + + case USBD_IDX_PRODUCT_STR: + USBD_GetString((uint8_t*)"USBDevice Product", str_desc, length); + return str_desc; + + case USBD_IDX_SERIAL_STR: { + // This document: http://www.usb.org/developers/docs/devclass_docs/usbmassbulk_10.pdf + // says that the serial number has to be at least 12 digits long and that + // the last 12 digits need to be unique. It also stipulates that the valid + // character set is that of upper-case hexadecimal digits. + // + // The onboard DFU bootloader produces a 12-digit serial number based on + // the 96-bit unique ID, so for consistency we go with this algorithm. + // You can see the serial number if you do: + // + // dfu-util -l + // + // See: https://my.st.com/52d187b7 for the algorithim used. + uint8_t *id = (uint8_t*)MP_HAL_UNIQUE_ID_ADDRESS; + char serial_buf[16]; + format_hex(&serial_buf[0], id[11]); + format_hex(&serial_buf[2], id[10] + id[2]); + format_hex(&serial_buf[4], id[9]); + format_hex(&serial_buf[6], id[8] + id[0]); + format_hex(&serial_buf[8], id[7]); + format_hex(&serial_buf[10], id[6]); + serial_buf[12] = '\0'; + + USBD_GetString((uint8_t*)serial_buf, str_desc, length); + return str_desc; + } + + case USBD_IDX_CONFIG_STR: + USBD_GetString((uint8_t*)FLASH_LAYOUT_STR, str_desc, length); + return str_desc; + + default: + return NULL; + } +} + +static const USBD_DescriptorsTypeDef pyb_usbdd_descriptors = { + pyb_usbdd_DeviceDescriptor, + pyb_usbdd_StrDescriptor, +}; + +static uint8_t pyb_usbdd_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + (void)self; + return USBD_OK; +} + +static uint8_t pyb_usbdd_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + (void)self; + return USBD_OK; +} + +static uint8_t pyb_usbdd_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + (void)self; + self->bRequest = req->bRequest; + self->wValue = req->wValue; + self->wLength = req->wLength; + if (req->bmRequest == 0x21) { + // host-to-device request + if (req->wLength == 0) { + // no data, process command straightaway + dfu_handle_rx(self->bRequest, self->wValue, 0, NULL); + } else { + // have data, prepare to receive it + USBD_CtlPrepareRx(pdev, self->rx_buf, req->wLength); + } + } else if (req->bmRequest == 0xa1) { + // device-to-host request + int len = dfu_handle_tx(self->bRequest, self->wValue, self->wLength, self->tx_buf, USB_TX_LEN); + if (len >= 0) { + self->tx_pending = true; + USBD_CtlSendData(&self->hUSBDDevice, self->tx_buf, len); + } + } + return USBD_OK; +} + +static uint8_t pyb_usbdd_EP0_TxSent(USBD_HandleTypeDef *pdev) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + self->tx_pending = false; + #if !USE_USB_POLLING + // Process now that we have sent a response + dfu_process(); + #endif + return USBD_OK; +} + +static uint8_t pyb_usbdd_EP0_RxReady(USBD_HandleTypeDef *pdev) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + dfu_handle_rx(self->bRequest, self->wValue, self->wLength, self->rx_buf); + return USBD_OK; +} + +static uint8_t *pyb_usbdd_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t *length) { + *length = sizeof(cfg_descr); + return (uint8_t*)cfg_descr; +} + +// this is used only in high-speed mode, which we don't support +static uint8_t *pyb_usbdd_GetDeviceQualifierDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + (void)self; + /* + *length = sizeof(USBD_CDC_MSC_HID_DeviceQualifierDesc); + return USBD_CDC_MSC_HID_DeviceQualifierDesc; + */ + *length = 0; + return NULL; +} + +static const USBD_ClassTypeDef pyb_usbdd_class = { + pyb_usbdd_Init, + pyb_usbdd_DeInit, + pyb_usbdd_Setup, + pyb_usbdd_EP0_TxSent, + pyb_usbdd_EP0_RxReady, + NULL, // pyb_usbdd_DataIn, + NULL, // pyb_usbdd_DataOut, + NULL, // SOF + NULL, // IsoINIncomplete + NULL, // IsoOUTIncomplete + pyb_usbdd_GetCfgDesc, + pyb_usbdd_GetCfgDesc, + pyb_usbdd_GetCfgDesc, + pyb_usbdd_GetDeviceQualifierDescriptor, +}; + +static pyb_usbdd_obj_t pyb_usbdd; + +static void pyb_usbdd_init(pyb_usbdd_obj_t *self, int phy_id) { + self->started = false; + USBD_HandleTypeDef *usbd = &self->hUSBDDevice; + usbd->id = phy_id; + usbd->dev_state = USBD_STATE_DEFAULT; + usbd->pDesc = (USBD_DescriptorsTypeDef*)&pyb_usbdd_descriptors; + usbd->pClass = &pyb_usbdd_class; + usbd->pClassData = self; +} + +static void pyb_usbdd_start(pyb_usbdd_obj_t *self) { + if (!self->started) { + USBD_LL_Init(&self->hUSBDDevice, 0); + USBD_LL_Start(&self->hUSBDDevice); + self->started = true; + } +} + +static void pyb_usbdd_stop(pyb_usbdd_obj_t *self) { + if (self->started) { + USBD_Stop(&self->hUSBDDevice); + self->started = false; + } +} + +static int pyb_usbdd_shutdown(void) { + pyb_usbdd_stop(&pyb_usbdd); + return 0; +} + +/******************************************************************************/ +// main + +#define RESET_MODE_LED_STATES 0x7421 + +static int get_reset_mode(void) { + usrbtn_init(); + int reset_mode = 1; + if (usrbtn_state()) { + // Cycle through reset modes while USR is held + systick_init(); + led_init(); + reset_mode = 0; + for (int i = 0; i < 1000; i++) { + if (i % 30 == 0) { + if (++reset_mode > 4) { + reset_mode = 1; + } + uint8_t l = RESET_MODE_LED_STATES >> ((reset_mode - 1) * 4); + led_state(LED0, l & 1); + led_state(LED1, l & 2); + led_state(LED2, l & 4); + } + if (!usrbtn_state()) { + break; + } + mp_hal_delay_ms(20); + } + // Flash the selected reset mode + for (int i = 0; i < 6; i++) { + led_state(LED0, 0); + led_state(LED1, 0); + led_state(LED2, 0); + mp_hal_delay_ms(50); + uint8_t l = RESET_MODE_LED_STATES >> ((reset_mode - 1) * 4); + led_state(LED0, l & 1); + led_state(LED1, l & 2); + led_state(LED2, l & 4); + mp_hal_delay_ms(50); + } + mp_hal_delay_ms(300); + } + return reset_mode; +} + +static void do_reset(void) { + led_state(LED0, 0); + led_state(LED1, 0); + led_state(LED2, 0); + mp_hal_delay_ms(50); + pyb_usbdd_shutdown(); + #if defined(MBOOT_I2C_SCL) + i2c_slave_shutdown(MBOOT_I2Cx, I2Cx_EV_IRQn); + #endif + mp_hal_delay_ms(50); + NVIC_SystemReset(); +} + +uint32_t SystemCoreClock; + +extern PCD_HandleTypeDef pcd_fs_handle; +extern PCD_HandleTypeDef pcd_hs_handle; + +void stm32_main(int initial_r0) { + #if defined(STM32F4) + #if INSTRUCTION_CACHE_ENABLE + __HAL_FLASH_INSTRUCTION_CACHE_ENABLE(); + #endif + #if DATA_CACHE_ENABLE + __HAL_FLASH_DATA_CACHE_ENABLE(); + #endif + #if PREFETCH_ENABLE + __HAL_FLASH_PREFETCH_BUFFER_ENABLE(); + #endif + #elif defined(STM32F7) + #if ART_ACCLERATOR_ENABLE + __HAL_FLASH_ART_ENABLE(); + #endif + #endif + + NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); + + #if USE_CACHE && defined(STM32F7) + SCB_EnableICache(); + SCB_EnableDCache(); + #endif + + #ifdef MBOOT_BOOTPIN_PIN + mp_hal_pin_config(MBOOT_BOOTPIN_PIN, MP_HAL_PIN_MODE_INPUT, MBOOT_BOOTPIN_PULL, 0); + if (mp_hal_pin_read(MBOOT_BOOTPIN_PIN) == MBOOT_BOOTPIN_ACTIVE) { + goto enter_bootloader; + } + #endif + + if ((initial_r0 & 0xffffff00) == 0x70ad0000) { + goto enter_bootloader; + } + + // MCU starts up with 16MHz HSI + SystemCoreClock = 16000000; + + int reset_mode = get_reset_mode(); + uint32_t msp = *(volatile uint32_t*)APPLICATION_ADDR; + if (reset_mode != 4 && (msp & APP_VALIDITY_BITS) == 0) { + // not DFU mode so jump to application, passing through reset_mode + // undo our DFU settings + // TODO probably should disable all IRQ sources first + #if USE_CACHE && defined(STM32F7) + SCB_DisableICache(); + SCB_DisableDCache(); + #endif + __set_MSP(msp); + ((void (*)(uint32_t)) *((volatile uint32_t*)(APPLICATION_ADDR + 4)))(reset_mode); + } + +enter_bootloader: + + // Init subsystems (get_reset_mode() may call these, calling them again is ok) + led_init(); + + // set the system clock to be HSE + SystemClock_Config(); + + #if USE_USB_POLLING + // irqs with a priority value greater or equal to "pri" will be disabled + // "pri" should be between 1 and 15 inclusive + uint32_t pri = 2; + pri <<= (8 - __NVIC_PRIO_BITS); + __ASM volatile ("msr basepri_max, %0" : : "r" (pri) : "memory"); + #endif + + #if 0 + #if defined(MICROPY_HW_BDEV_IOCTL) + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_INIT, 0); + #endif + + #if defined(MICROPY_HW_BDEV2_IOCTL) + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_INIT, 0); + #endif + #endif + + dfu_init(); + + pyb_usbdd_init(&pyb_usbdd, MICROPY_HW_USB_MAIN_DEV); + pyb_usbdd_start(&pyb_usbdd); + + #if defined(MBOOT_I2C_SCL) + initial_r0 &= 0x7f; + if (initial_r0 == 0) { + initial_r0 = 0x23; // Default I2C address + } + i2c_init(initial_r0); + #endif + + led_state(LED0, 0); + led_state(LED1, 0); + led_state(LED2, 0); + + #if USE_USB_POLLING + uint32_t ss = systick_ms; + int ss2 = -1; + #endif + for (;;) { + #if USE_USB_POLLING + #if defined(MICROPY_HW_USB_FS) + if (pcd_fs_handle.Instance->GINTSTS & pcd_fs_handle.Instance->GINTMSK) { + HAL_PCD_IRQHandler(&pcd_fs_handle); + } + #endif + #if defined(MICROPY_HW_USB_HS) + if (pcd_hs_handle.Instance->GINTSTS & pcd_hs_handle.Instance->GINTMSK) { + HAL_PCD_IRQHandler(&pcd_hs_handle); + } + #endif + if (!pyb_usbdd.tx_pending) { + dfu_process(); + } + #endif + + #if USE_USB_POLLING + //__WFI(); // slows it down way too much; might work with 10x faster systick + if (systick_ms - ss > 50) { + ss += 50; + ss2 = (ss2 + 1) % 20; + switch (ss2) { + case 0: led_state(LED0, 1); break; + case 1: led_state(LED0, 0); break; + } + } + #else + led_state(LED0, 1); + mp_hal_delay_ms(50); + led_state(LED0, 0); + mp_hal_delay_ms(950); + #endif + } +} + +void NMI_Handler(void) { +} + +void MemManage_Handler(void) { + while (1) { + __fatal_error("MemManage"); + } +} + +void BusFault_Handler(void) { + while (1) { + __fatal_error("BusFault"); + } +} + +void UsageFault_Handler(void) { + while (1) { + __fatal_error("UsageFault"); + } +} + +void SVC_Handler(void) { +} + +void DebugMon_Handler(void) { +} + +void PendSV_Handler(void) { +} + +void SysTick_Handler(void) { + systick_ms += 1; + + // Read the systick control regster. This has the side effect of clearing + // the COUNTFLAG bit, which makes the logic in mp_hal_ticks_us + // work properly. + SysTick->CTRL; +} + +#if defined(MBOOT_I2C_SCL) +void I2Cx_EV_IRQHandler(void) { + i2c_slave_ev_irq_handler(MBOOT_I2Cx); +} +#endif + +#if !USE_USB_POLLING +#if defined(MICROPY_HW_USB_FS) +void OTG_FS_IRQHandler(void) { + HAL_PCD_IRQHandler(&pcd_fs_handle); +} +#endif +#if defined(MICROPY_HW_USB_HS) +void OTG_HS_IRQHandler(void) { + HAL_PCD_IRQHandler(&pcd_hs_handle); +} +#endif +#endif diff --git a/ports/stm32/mboot/mboot.py b/ports/stm32/mboot/mboot.py new file mode 100644 index 0000000000..39ae0f6f2d --- /dev/null +++ b/ports/stm32/mboot/mboot.py @@ -0,0 +1,177 @@ +# Driver for Mboot, the MicroPython boot loader +# MIT license; Copyright (c) 2018 Damien P. George + +import struct, time, os, hashlib + + +I2C_CMD_ECHO = 1 +I2C_CMD_GETID = 2 +I2C_CMD_GETCAPS = 3 +I2C_CMD_RESET = 4 +I2C_CMD_CONFIG = 5 +I2C_CMD_GETLAYOUT = 6 +I2C_CMD_MASSERASE = 7 +I2C_CMD_PAGEERASE = 8 +I2C_CMD_SETRDADDR = 9 +I2C_CMD_SETWRADDR = 10 +I2C_CMD_READ = 11 +I2C_CMD_WRITE = 12 +I2C_CMD_COPY = 13 +I2C_CMD_CALCHASH = 14 +I2C_CMD_MARKVALID = 15 + + +class Bootloader: + def __init__(self, i2c, addr): + self.i2c = i2c + self.addr = addr + self.buf1 = bytearray(1) + try: + self.i2c.writeto(addr, b'') + except OSError: + raise Exception('no I2C mboot device found') + + def wait_response(self): + start = time.ticks_ms() + while 1: + try: + self.i2c.readfrom_into(self.addr, self.buf1) + n = self.buf1[0] + break + except OSError as er: + time.sleep_us(500) + if time.ticks_diff(time.ticks_ms(), start) > 5000: + raise Exception('timeout') + if n >= 129: + raise Exception(n) + if n == 0: + return b'' + else: + return self.i2c.readfrom(self.addr, n) + + def wait_empty_response(self): + ret = self.wait_response() + if ret: + raise Exception('expected empty response got %r' % ret) + else: + return None + + def echo(self, data): + self.i2c.writeto(self.addr, struct.pack(' + +#define mp_hal_delay_us_fast(us) mp_hal_delay_us(us) + +#define MP_HAL_PIN_MODE_INPUT (0) +#define MP_HAL_PIN_MODE_OUTPUT (1) +#define MP_HAL_PIN_MODE_ALT (2) +#define MP_HAL_PIN_MODE_ANALOG (3) +#define MP_HAL_PIN_MODE_OPEN_DRAIN (5) +#define MP_HAL_PIN_MODE_ALT_OPEN_DRAIN (6) +#define MP_HAL_PIN_PULL_NONE (GPIO_NOPULL) +#define MP_HAL_PIN_PULL_UP (GPIO_PULLUP) +#define MP_HAL_PIN_PULL_DOWN (GPIO_PULLDOWN) + +#define mp_hal_pin_obj_t uint32_t +#define mp_hal_pin_input(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0) +#define mp_hal_pin_output(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0) +#define mp_hal_pin_open_drain(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_OPEN_DRAIN, MP_HAL_PIN_PULL_NONE, 0) +#define mp_hal_pin_low(p) (((GPIO_TypeDef*)((p) & ~0xf))->BSRR = 0x10000 << ((p) & 0xf)) +#define mp_hal_pin_high(p) (((GPIO_TypeDef*)((p) & ~0xf))->BSRR = 1 << ((p) & 0xf)) +#define mp_hal_pin_od_low(p) mp_hal_pin_low(p) +#define mp_hal_pin_od_high(p) mp_hal_pin_high(p) +#define mp_hal_pin_read(p) ((((GPIO_TypeDef*)((p) & ~0xf))->IDR >> ((p) & 0xf)) & 1) +#define mp_hal_pin_write(p, v) do { if (v) { mp_hal_pin_high(p); } else { mp_hal_pin_low(p); } } while (0) + +void mp_hal_pin_config(uint32_t port_pin, uint32_t mode, uint32_t pull, uint32_t alt); +void mp_hal_pin_config_speed(uint32_t port_pin, uint32_t speed); + +#define pin_A0 (GPIOA_BASE | 0) +#define pin_A1 (GPIOA_BASE | 1) +#define pin_A2 (GPIOA_BASE | 2) +#define pin_A3 (GPIOA_BASE | 3) +#define pin_A4 (GPIOA_BASE | 4) +#define pin_A5 (GPIOA_BASE | 5) +#define pin_A6 (GPIOA_BASE | 6) +#define pin_A7 (GPIOA_BASE | 7) +#define pin_A8 (GPIOA_BASE | 8) +#define pin_A9 (GPIOA_BASE | 9) +#define pin_A10 (GPIOA_BASE | 10) +#define pin_A11 (GPIOA_BASE | 11) +#define pin_A12 (GPIOA_BASE | 12) +#define pin_A13 (GPIOA_BASE | 13) +#define pin_A14 (GPIOA_BASE | 14) +#define pin_A15 (GPIOA_BASE | 15) + +#define pin_B0 (GPIOB_BASE | 0) +#define pin_B1 (GPIOB_BASE | 1) +#define pin_B2 (GPIOB_BASE | 2) +#define pin_B3 (GPIOB_BASE | 3) +#define pin_B4 (GPIOB_BASE | 4) +#define pin_B5 (GPIOB_BASE | 5) +#define pin_B6 (GPIOB_BASE | 6) +#define pin_B7 (GPIOB_BASE | 7) +#define pin_B8 (GPIOB_BASE | 8) +#define pin_B9 (GPIOB_BASE | 9) +#define pin_B10 (GPIOB_BASE | 10) +#define pin_B11 (GPIOB_BASE | 11) +#define pin_B12 (GPIOB_BASE | 12) +#define pin_B13 (GPIOB_BASE | 13) +#define pin_B14 (GPIOB_BASE | 14) +#define pin_B15 (GPIOB_BASE | 15) + +#define pin_C0 (GPIOC_BASE | 0) +#define pin_C1 (GPIOC_BASE | 1) +#define pin_C2 (GPIOC_BASE | 2) +#define pin_C3 (GPIOC_BASE | 3) +#define pin_C4 (GPIOC_BASE | 4) +#define pin_C5 (GPIOC_BASE | 5) +#define pin_C6 (GPIOC_BASE | 6) +#define pin_C7 (GPIOC_BASE | 7) +#define pin_C8 (GPIOC_BASE | 8) +#define pin_C9 (GPIOC_BASE | 9) +#define pin_C10 (GPIOC_BASE | 10) +#define pin_C11 (GPIOC_BASE | 11) +#define pin_C12 (GPIOC_BASE | 12) +#define pin_C13 (GPIOC_BASE | 13) +#define pin_C14 (GPIOC_BASE | 14) +#define pin_C15 (GPIOC_BASE | 15) + +#define pin_D0 (GPIOD_BASE | 0) +#define pin_D1 (GPIOD_BASE | 1) +#define pin_D2 (GPIOD_BASE | 2) +#define pin_D3 (GPIOD_BASE | 3) +#define pin_D4 (GPIOD_BASE | 4) +#define pin_D5 (GPIOD_BASE | 5) +#define pin_D6 (GPIOD_BASE | 6) +#define pin_D7 (GPIOD_BASE | 7) +#define pin_D8 (GPIOD_BASE | 8) +#define pin_D9 (GPIOD_BASE | 9) +#define pin_D10 (GPIOD_BASE | 10) +#define pin_D11 (GPIOD_BASE | 11) +#define pin_D12 (GPIOD_BASE | 12) +#define pin_D13 (GPIOD_BASE | 13) +#define pin_D14 (GPIOD_BASE | 14) +#define pin_D15 (GPIOD_BASE | 15) + +#define pin_E0 (GPIOE_BASE | 0) +#define pin_E1 (GPIOE_BASE | 1) +#define pin_E2 (GPIOE_BASE | 2) +#define pin_E3 (GPIOE_BASE | 3) +#define pin_E4 (GPIOE_BASE | 4) +#define pin_E5 (GPIOE_BASE | 5) +#define pin_E6 (GPIOE_BASE | 6) +#define pin_E7 (GPIOE_BASE | 7) +#define pin_E8 (GPIOE_BASE | 8) +#define pin_E9 (GPIOE_BASE | 9) +#define pin_E10 (GPIOE_BASE | 10) +#define pin_E11 (GPIOE_BASE | 11) +#define pin_E12 (GPIOE_BASE | 12) +#define pin_E13 (GPIOE_BASE | 13) +#define pin_E14 (GPIOE_BASE | 14) +#define pin_E15 (GPIOE_BASE | 15) + +#define pin_F0 (GPIOF_BASE | 0) +#define pin_F1 (GPIOF_BASE | 1) +#define pin_F2 (GPIOF_BASE | 2) +#define pin_F3 (GPIOF_BASE | 3) +#define pin_F4 (GPIOF_BASE | 4) +#define pin_F5 (GPIOF_BASE | 5) +#define pin_F6 (GPIOF_BASE | 6) +#define pin_F7 (GPIOF_BASE | 7) +#define pin_F8 (GPIOF_BASE | 8) +#define pin_F9 (GPIOF_BASE | 9) +#define pin_F10 (GPIOF_BASE | 10) +#define pin_F11 (GPIOF_BASE | 11) +#define pin_F12 (GPIOF_BASE | 12) +#define pin_F13 (GPIOF_BASE | 13) +#define pin_F14 (GPIOF_BASE | 14) +#define pin_F15 (GPIOF_BASE | 15) diff --git a/ports/stm32/mboot/stm32_generic.ld b/ports/stm32/mboot/stm32_generic.ld new file mode 100644 index 0000000000..8585c68734 --- /dev/null +++ b/ports/stm32/mboot/stm32_generic.ld @@ -0,0 +1,77 @@ +/* + GNU linker script for generic STM32xxx MCU +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH_BL (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 (can be 32K) */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; + +/* Define tho top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +ENTRY(Reset_Handler) + +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH_BL + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text*) + *(.rodata*) + . = ALIGN(4); + _etext = .; + } >FLASH_BL + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data section */ + .data : + { + . = ALIGN(4); + _sdata = .; + *(.data*) + + . = ALIGN(4); + _edata = .; + } >RAM AT> FLASH_BL + + /* Uninitialized data section */ + .bss : + { + . = ALIGN(4); + _sbss = .; + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; + } >RAM + + /* this just checks there is enough RAM for the stack */ + .stack : + { + . = ALIGN(4); + . = . + _minimum_stack_size; + . = ALIGN(4); + } >RAM + + .ARM.attributes 0 : { *(.ARM.attributes) } +} From dfeaea144168c3ec3b4ec513cfb201ce93f99f5e Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 25 May 2018 10:59:40 +1000 Subject: [PATCH 719/828] py/objtype: Remove TODO comment about needing to check for property. Instance members are always treated as values, even if they are properties. A test is added to show this is the case. --- py/objtype.c | 1 - tests/basics/builtin_property.py | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/py/objtype.c b/py/objtype.c index 7df349ce9b..2ec27c762c 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -562,7 +562,6 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); if (elem != NULL) { // object member, always treated as a value - // TODO should we check for properties? dest[0] = elem->value; return; } diff --git a/tests/basics/builtin_property.py b/tests/basics/builtin_property.py index 89c3d49364..4b08ee9d3b 100644 --- a/tests/basics/builtin_property.py +++ b/tests/basics/builtin_property.py @@ -105,3 +105,9 @@ class E: # not tested for because the other keyword arguments are not accepted # q = property(fget=lambda self: 21, doc="Half the truth.") print(E().p) + +# a property as an instance member should not be delegated to +class F: + def __init__(self): + self.prop_member = property() +print(type(F().prop_member)) From ef4c8e6e971da0aa40d555f6875003290d1d4c3f Mon Sep 17 00:00:00 2001 From: Nick Moore Date: Thu, 24 May 2018 20:37:53 +1000 Subject: [PATCH 720/828] esp32: Silence ESP-IDF log messages when in raw REPL mode. This prevents clients such as ampy, mpy-utils, etc getting confused by extraneous data. --- ports/esp32/main.c | 9 +++++++++ ports/esp32/modnetwork.c | 12 +++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/ports/esp32/main.c b/ports/esp32/main.c index 2fa86fd3c9..e7290c7eb8 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -28,6 +28,7 @@ #include #include +#include #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -35,6 +36,7 @@ #include "nvs_flash.h" #include "esp_task.h" #include "soc/cpu.h" +#include "esp_log.h" #include "py/stackctrl.h" #include "py/nlr.h" @@ -58,6 +60,11 @@ STATIC StaticTask_t mp_task_tcb; STATIC StackType_t mp_task_stack[MP_TASK_STACK_LEN] __attribute__((aligned (8))); +int vprintf_null(const char *format, va_list ap) { + // do nothing: this is used as a log target during raw repl mode + return 0; +} + void mp_task(void *pvParameter) { volatile uint32_t sp = (uint32_t)get_sp(); #if MICROPY_PY_THREAD @@ -93,9 +100,11 @@ soft_reset: for (;;) { if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + vprintf_like_t vprintf_log = esp_log_set_vprintf(vprintf_null); if (pyexec_raw_repl() != 0) { break; } + esp_log_set_vprintf(vprintf_log); } else { if (pyexec_friendly_repl() != 0) { break; diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index 8a2e266c62..9f7aa77dfa 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -139,24 +139,26 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) { // This is a workaround as ESP32 WiFi libs don't currently // auto-reassociate. system_event_sta_disconnected_t *disconn = &event->event_info.disconnected; - ESP_LOGI("wifi", "STA_DISCONNECTED, reason:%d", disconn->reason); + char *message = ""; switch (disconn->reason) { case WIFI_REASON_BEACON_TIMEOUT: - mp_printf(MP_PYTHON_PRINTER, "beacon timeout\n"); // AP has dropped out; try to reconnect. + message = "\nbeacon timeout"; break; case WIFI_REASON_NO_AP_FOUND: - mp_printf(MP_PYTHON_PRINTER, "no AP found\n"); // AP may not exist, or it may have momentarily dropped out; try to reconnect. + message = "\nno AP found"; break; case WIFI_REASON_AUTH_FAIL: - mp_printf(MP_PYTHON_PRINTER, "authentication failed\n"); + message = "\nauthentication failed"; wifi_sta_connected = false; break; default: // Let other errors through and try to reconnect. break; } + ESP_LOGI("wifi", "STA_DISCONNECTED, reason:%d%s", disconn->reason, message); + if (wifi_sta_connected) { wifi_mode_t mode; if (esp_wifi_get_mode(&mode) == ESP_OK) { @@ -164,7 +166,7 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) { // STA is active so attempt to reconnect. esp_err_t e = esp_wifi_connect(); if (e != ESP_OK) { - mp_printf(MP_PYTHON_PRINTER, "error attempting to reconnect: 0x%04x", e); + ESP_LOGI("wifi", "error attempting to reconnect: 0x%04x", e); } } } From aa4a7a8732a8594c932503b50152f8e60053e498 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 28 May 2018 10:46:49 +1000 Subject: [PATCH 721/828] stm32/usb: Guard USB device code with #if for whether USB is enabled. With this change, all the USB source code can now be passed through the compiler even if the MCU does not have a USB peripheral. --- ports/stm32/stm32_it.c | 4 ++++ ports/stm32/usbd_cdc_interface.c | 4 ++++ ports/stm32/usbd_conf.c | 4 ++++ ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index d2cd0788a4..b7124de894 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -84,8 +84,12 @@ #include "usb.h" extern void __fatal_error(const char*); +#if defined(MICROPY_HW_USB_FS) extern PCD_HandleTypeDef pcd_fs_handle; +#endif +#if defined(MICROPY_HW_USB_HS) extern PCD_HandleTypeDef pcd_hs_handle; +#endif /******************************************************************************/ /* Cortex-M4 Processor Exceptions Handlers */ diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c index 4c464dbf33..91ae81bb32 100644 --- a/ports/stm32/usbd_cdc_interface.c +++ b/ports/stm32/usbd_cdc_interface.c @@ -45,6 +45,8 @@ #include "lib/utils/interrupt_char.h" #include "irq.h" +#if MICROPY_HW_ENABLE_USB + // CDC control commands #define CDC_SEND_ENCAPSULATED_COMMAND 0x00 #define CDC_GET_ENCAPSULATED_RESPONSE 0x01 @@ -360,3 +362,5 @@ int usbd_cdc_rx(usbd_cdc_itf_t *cdc, uint8_t *buf, uint32_t len, uint32_t timeou // Success, return number of bytes read return len; } + +#endif diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index 7829dcce68..41a8353047 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -35,6 +35,8 @@ #include "irq.h" #include "usb.h" +#if MICROPY_HW_USB_FS || MICROPY_HW_USB_HS + #if MICROPY_HW_USB_FS PCD_HandleTypeDef pcd_fs_handle; #endif @@ -663,4 +665,6 @@ void USBD_LL_Delay(uint32_t Delay) { HAL_Delay(Delay); } +#endif // MICROPY_HW_USB_FS || MICROPY_HW_USB_HS + /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c index b75e5d0c54..c5aac037d3 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -28,6 +28,8 @@ #include "usbd_ioreq.h" #include "usbd_cdc_msc_hid.h" +#if MICROPY_HW_ENABLE_USB + #define MSC_TEMPLATE_CONFIG_DESC_SIZE (32) #define MSC_TEMPLATE_MSC_DESC_OFFSET (9) #define CDC_TEMPLATE_CONFIG_DESC_SIZE (67) @@ -1312,3 +1314,5 @@ const USBD_ClassTypeDef USBD_CDC_MSC_HID = { USBD_CDC_MSC_HID_GetCfgDesc, USBD_CDC_MSC_HID_GetDeviceQualifierDescriptor, }; + +#endif From f497723802406c00d84b20fe5fc74b973a128ebc Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 28 May 2018 10:57:27 +1000 Subject: [PATCH 722/828] stm32: Allow to have no storage support if there are no block devices. If no block devices are defined by a board then storage support will be disabled. This means there is no filesystem provided by either the internal flash or external SPI flash. But the VFS system can still be enabled and filesystems provided on external devices like an SD card. --- ports/stm32/main.c | 11 ++++++++++- ports/stm32/modmachine.c | 2 ++ ports/stm32/mpconfigboard_common.h | 7 +++++++ ports/stm32/spibdev.c | 4 ++++ ports/stm32/stm32_it.c | 4 ++++ ports/stm32/storage.c | 4 ++++ 6 files changed, 31 insertions(+), 1 deletion(-) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 5c75355422..d24200ba0f 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -130,6 +130,7 @@ STATIC mp_obj_t pyb_main(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_a } MP_DEFINE_CONST_FUN_OBJ_KW(pyb_main_obj, 1, pyb_main); +#if MICROPY_HW_ENABLE_STORAGE static const char fresh_boot_py[] = "# boot.py -- run on boot-up\r\n" "# can run arbitrary Python, but best to keep it minimal\r\n" @@ -264,6 +265,7 @@ MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { return true; } +#endif #if MICROPY_HW_HAS_SDCARD STATIC bool init_sdcard_fs(void) { @@ -512,7 +514,9 @@ void stm32_main(uint32_t reset_mode) { #if MICROPY_HW_HAS_SDCARD sdcard_init(); #endif + #if MICROPY_HW_ENABLE_STORAGE storage_init(); + #endif #if MICROPY_PY_LWIP // lwIP doesn't allow to reinitialise itself by subsequent calls to this function // because the system timeout list (next_timeout) is only ever reset by BSS clearing. @@ -599,7 +603,10 @@ soft_reset: // Initialise the local flash filesystem. // Create it if needed, mount in on /flash, and set it as current dir. - bool mounted_flash = init_flash_fs(reset_mode); + bool mounted_flash = false; + #if MICROPY_HW_ENABLE_STORAGE + mounted_flash = init_flash_fs(reset_mode); + #endif bool mounted_sdcard = false; #if MICROPY_HW_HAS_SDCARD @@ -727,8 +734,10 @@ soft_reset_exit: // soft reset + #if MICROPY_HW_ENABLE_STORAGE printf("PYB: sync filesystems\n"); storage_flush(); + #endif printf("PYB: soft reboot\n"); #if MICROPY_PY_NETWORK diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index 73442719b5..ff1eaec95f 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -231,7 +231,9 @@ STATIC NORETURN mp_obj_t machine_bootloader(void) { #if MICROPY_HW_ENABLE_USB pyb_usb_dev_deinit(); #endif + #if MICROPY_HW_ENABLE_STORAGE storage_flush(); + #endif HAL_RCC_DeInit(); HAL_DeInit(); diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 7449a68956..919598de44 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -169,6 +169,13 @@ #define MICROPY_HW_BDEV_WRITEBLOCK flash_bdev_writeblock #endif +// Enable the storage sub-system if a block device is defined +#if defined(MICROPY_HW_BDEV_IOCTL) +#define MICROPY_HW_ENABLE_STORAGE (1) +#else +#define MICROPY_HW_ENABLE_STORAGE (0) +#endif + // Enable hardware I2C if there are any peripherals defined #if defined(MICROPY_HW_I2C1_SCL) || defined(MICROPY_HW_I2C2_SCL) \ || defined(MICROPY_HW_I2C3_SCL) || defined(MICROPY_HW_I2C4_SCL) diff --git a/ports/stm32/spibdev.c b/ports/stm32/spibdev.c index 91ec4df5e9..b73058c6ab 100644 --- a/ports/stm32/spibdev.c +++ b/ports/stm32/spibdev.c @@ -30,6 +30,8 @@ #include "led.h" #include "storage.h" +#if MICROPY_HW_ENABLE_STORAGE + int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) { switch (op) { case BDEV_IOCTL_INIT: @@ -79,3 +81,5 @@ int spi_bdev_writeblocks(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_nu return ret; } + +#endif diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index b7124de894..b051382875 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -310,9 +310,11 @@ void SysTick_Handler(void) { // be generalised in the future then a dispatch table can be used as // follows: ((void(*)(void))(systick_dispatch[uwTick & 0xf]))(); + #if MICROPY_HW_ENABLE_STORAGE if (STORAGE_IDLE_TICK(uwTick)) { NVIC->STIR = FLASH_IRQn; } + #endif if (DMA_IDLE_ENABLED() && DMA_IDLE_TICK(uwTick)) { dma_idle_handler(uwTick); @@ -459,8 +461,10 @@ void FLASH_IRQHandler(void) { HAL_FLASH_IRQHandler(); } */ + #if MICROPY_HW_ENABLE_STORAGE // This call the storage IRQ handler, to check if the flash cache needs flushing storage_irq_handler(); + #endif IRQ_EXIT(FLASH_IRQn); } diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index 2ac54a4010..761db0b525 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -34,6 +34,8 @@ #include "storage.h" #include "irq.h" +#if MICROPY_HW_ENABLE_STORAGE + #define FLASH_PART1_START_BLOCK (0x100) #if defined(MICROPY_HW_BDEV2_IOCTL) @@ -284,3 +286,5 @@ void pyb_flash_init_vfs(fs_user_mount_t *vfs) { vfs->u.ioctl[0] = (mp_obj_t)&pyb_flash_ioctl_obj; vfs->u.ioctl[1] = (mp_obj_t)&pyb_flash_obj; } + +#endif From 070937fe930d5fd19ed9d0f37172d38d8a3d9920 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 28 May 2018 11:23:33 +1000 Subject: [PATCH 723/828] stm32: Add support for Cortex-M0 CPUs. --- ports/stm32/gchelper_m0.s | 61 +++++++++++++++++++++++++++++ ports/stm32/irq.h | 20 ++++++++++ ports/stm32/main.c | 2 + ports/stm32/mphalport.c | 2 + ports/stm32/mphalport.h | 10 +++++ ports/stm32/resethandler_m0.s | 74 +++++++++++++++++++++++++++++++++++ ports/stm32/stm32_it.c | 14 +++++++ 7 files changed, 183 insertions(+) create mode 100644 ports/stm32/gchelper_m0.s create mode 100644 ports/stm32/resethandler_m0.s diff --git a/ports/stm32/gchelper_m0.s b/ports/stm32/gchelper_m0.s new file mode 100644 index 0000000000..db0d9738d1 --- /dev/null +++ b/ports/stm32/gchelper_m0.s @@ -0,0 +1,61 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + .syntax unified + .cpu cortex-m0 + .thumb + + .section .text + .align 2 + + .global gc_helper_get_regs_and_sp + .type gc_helper_get_regs_and_sp, %function + +@ uint gc_helper_get_regs_and_sp(r0=uint regs[10]) +gc_helper_get_regs_and_sp: + @ store registers into given array + str r4, [r0, #0] + str r5, [r0, #4] + str r6, [r0, #8] + str r7, [r0, #12] + mov r1, r8 + str r1, [r0, #16] + mov r1, r9 + str r1, [r0, #20] + mov r1, r10 + str r1, [r0, #24] + mov r1, r11 + str r1, [r0, #28] + mov r1, r12 + str r1, [r0, #32] + mov r1, r13 + str r1, [r0, #36] + + @ return the sp + mov r0, sp + bx lr + + .size gc_helper_get_regs_and_sp, .-gc_helper_get_regs_and_sp diff --git a/ports/stm32/irq.h b/ports/stm32/irq.h index 1b68a5488e..3fe20867fe 100644 --- a/ports/stm32/irq.h +++ b/ports/stm32/irq.h @@ -102,6 +102,24 @@ MP_DECLARE_CONST_FUN_OBJ_0(pyb_irq_stats_obj); // The following interrupts are arranged from highest priority to lowest // priority to make it a bit easier to figure out. +#if __CORTEX_M == 0 + +//#def IRQ_PRI_SYSTICK 0 +#define IRQ_PRI_UART 1 +#define IRQ_PRI_FLASH 1 +#define IRQ_PRI_SDIO 1 +#define IRQ_PRI_DMA 1 +#define IRQ_PRI_OTG_FS 2 +#define IRQ_PRI_OTG_HS 2 +#define IRQ_PRI_TIM5 2 +#define IRQ_PRI_CAN 2 +#define IRQ_PRI_TIMX 2 +#define IRQ_PRI_EXTINT 2 +#define IRQ_PRI_PENDSV 3 +#define IRQ_PRI_RTC_WKUP 3 + +#else + //#def IRQ_PRI_SYSTICK NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 0, 0) // The UARTs have no FIFOs, so if they don't get serviced quickly then characters @@ -135,4 +153,6 @@ MP_DECLARE_CONST_FUN_OBJ_0(pyb_irq_stats_obj); #define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) #define IRQ_PRI_RTC_WKUP NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) +#endif + #endif // MICROPY_INCLUDED_STM32_IRQ_H diff --git a/ports/stm32/main.c b/ports/stm32/main.c index d24200ba0f..19c77453f9 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -458,8 +458,10 @@ void stm32_main(uint32_t reset_mode) { #endif + #if __CORTEX_M >= 0x03 // Set the priority grouping NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); + #endif // SysTick is needed by HAL_RCC_ClockConfig (called in SystemClock_Config) HAL_InitTick(TICK_INT_PRIORITY); diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c index b7636ce270..2bf10ad479 100644 --- a/ports/stm32/mphalport.c +++ b/ports/stm32/mphalport.c @@ -87,6 +87,7 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { } } +#if __CORTEX_M >= 0x03 void mp_hal_ticks_cpu_enable(void) { if (!(DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk)) { CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; @@ -98,6 +99,7 @@ void mp_hal_ticks_cpu_enable(void) { DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; } } +#endif void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) { #if defined(STM32L476xx) || defined(STM32L496xx) diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h index 511a76cd0c..72413c04c7 100644 --- a/ports/stm32/mphalport.h +++ b/ports/stm32/mphalport.h @@ -11,16 +11,26 @@ void mp_hal_set_interrupt_char(int c); // -1 to disable #include "irq.h" +#if __CORTEX_M == 0 +// Don't have raise_irq_pri on Cortex-M0 so keep IRQs enabled to have SysTick timing +#define mp_hal_quiet_timing_enter() (1) +#define mp_hal_quiet_timing_exit(irq_state) (void)(irq_state) +#else #define mp_hal_quiet_timing_enter() raise_irq_pri(1) #define mp_hal_quiet_timing_exit(irq_state) restore_irq_pri(irq_state) +#endif #define mp_hal_delay_us_fast(us) mp_hal_delay_us(us) void mp_hal_ticks_cpu_enable(void); static inline mp_uint_t mp_hal_ticks_cpu(void) { + #if __CORTEX_M == 0 + return 0; + #else if (!(DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk)) { mp_hal_ticks_cpu_enable(); } return DWT->CYCCNT; + #endif } // C-level pin HAL diff --git a/ports/stm32/resethandler_m0.s b/ports/stm32/resethandler_m0.s new file mode 100644 index 0000000000..bb88e8daef --- /dev/null +++ b/ports/stm32/resethandler_m0.s @@ -0,0 +1,74 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + .syntax unified + .cpu cortex-m0 + .thumb + + .section .text.Reset_Handler + .global Reset_Handler + .type Reset_Handler, %function + +Reset_Handler: + /* Save the first argument to pass through to stm32_main */ + mov r4, r0 + + /* Load the stack pointer */ + ldr r0, =_estack + mov sp, r0 + + /* Initialise the data section */ + ldr r1, =_sidata + ldr r2, =_sdata + ldr r3, =_edata + b .data_copy_entry +.data_copy_loop: + ldr r0, [r1] + adds r1, #4 + str r0, [r2] + adds r2, #4 +.data_copy_entry: + cmp r2, r3 + bcc .data_copy_loop + + /* Zero out the BSS section */ + movs r0, #0 + ldr r1, =_sbss + ldr r2, =_ebss + b .bss_zero_entry +.bss_zero_loop: + str r0, [r1] + adds r1, #4 +.bss_zero_entry: + cmp r1, r2 + bcc .bss_zero_loop + + /* Initialise the system and jump to the main code */ + bl SystemInit + mov r0, r4 + bl stm32_main + + .size Reset_Handler, .-Reset_Handler diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index b051382875..8202209775 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -165,6 +165,7 @@ void HardFault_C_Handler(ExceptionRegisters_t *regs) { print_reg("PC ", regs->pc); print_reg("XPSR ", regs->xpsr); + #if __CORTEX_M >= 3 uint32_t cfsr = SCB->CFSR; print_reg("HFSR ", SCB->HFSR); @@ -175,6 +176,7 @@ void HardFault_C_Handler(ExceptionRegisters_t *regs) { if (cfsr & 0x8000) { print_reg("BFAR ", SCB->BFAR); } + #endif if ((void*)&_ram_start <= (void*)regs && (void*)regs < (void*)&_ram_end) { mp_hal_stdout_tx_str("Stack:\r\n"); @@ -207,6 +209,17 @@ void HardFault_Handler(void) { // main stack pointer (aka MSP). If CONTROL.SPSEL is 1, then the exception // was stacked up using the process stack pointer (aka PSP). + #if __CORTEX_M == 0 + __asm volatile( + " mov r0, lr \n" + " lsr r0, r0, #3 \n" // Shift Bit 3 into carry to see which stack pointer we should use. + " mrs r0, msp \n" // Make R0 point to main stack pointer + " bcc .use_msp \n" // Keep MSP in R0 if SPSEL (carry) is 0 + " mrs r0, psp \n" // Make R0 point to process stack pointer + " .use_msp: \n" + " b HardFault_C_Handler \n" // Off to C land + ); + #else __asm volatile( " tst lr, #4 \n" // Test Bit 3 to see which stack pointer we should use. " ite eq \n" // Tell the assembler that the nest 2 instructions are if-then-else @@ -214,6 +227,7 @@ void HardFault_Handler(void) { " mrsne r0, psp \n" // Make R0 point to process stack pointer " b HardFault_C_Handler \n" // Off to C land ); + #endif } /** From 5c0685912f8efc4e8345999aab647662a5875759 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 28 May 2018 11:57:17 +1000 Subject: [PATCH 724/828] stm32/timer: Make timer_get_source_freq more efficient by using regs. Use direct register access to get the APB clock divider. This reduces code size and makes the code more efficient. --- ports/stm32/timer.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c index b220bec5ff..fd719b2f2c 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -228,25 +228,27 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { // APB clock. Otherwise (APB prescaler > 1) the timer clock is twice its // respective APB clock. See DM00031020 Rev 4, page 115. uint32_t timer_get_source_freq(uint32_t tim_id) { - uint32_t source; - uint32_t latency; - RCC_ClkInitTypeDef rcc_init; - - // Get clock config. - HAL_RCC_GetClockConfig(&rcc_init, &latency); - + uint32_t source, clk_div; if (tim_id == 1 || (8 <= tim_id && tim_id <= 11)) { // TIM{1,8,9,10,11} are on APB2 source = HAL_RCC_GetPCLK2Freq(); - if (rcc_init.APB2CLKDivider != RCC_HCLK_DIV1) { - source *= 2; - } + #if defined(STM32H7) + clk_div = RCC->D2CFGR & RCC_D2CFGR_D2PPRE2; + #else + clk_div = RCC->CFGR & RCC_CFGR_PPRE2; + #endif } else { // TIM{2,3,4,5,6,7,12,13,14} are on APB1 source = HAL_RCC_GetPCLK1Freq(); - if (rcc_init.APB1CLKDivider != RCC_HCLK_DIV1) { - source *= 2; - } + #if defined(STM32H7) + clk_div = RCC->D2CFGR & RCC_D2CFGR_D2PPRE1; + #else + clk_div = RCC->CFGR & RCC_CFGR_PPRE1; + #endif + } + if (clk_div != 0) { + // APB prescaler for this timer is > 1 + source *= 2; } return source; } From 6d83468a30f79be9baec297c38506da6517732b5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 28 May 2018 12:01:52 +1000 Subject: [PATCH 725/828] stm32: Allow a board to disable MICROPY_VFS_FAT. --- ports/stm32/modmachine.c | 2 ++ ports/stm32/moduos.c | 4 ++++ ports/stm32/mpconfigport.h | 4 +++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index ff1eaec95f..d8054c3f25 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -181,6 +181,7 @@ STATIC mp_obj_t machine_info(size_t n_args, const mp_obj_t *args) { // free space on flash { + #if MICROPY_VFS_FAT for (mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) { if (strncmp("/flash", vfs->str, vfs->len) == 0) { // assumes that it's a FatFs filesystem @@ -191,6 +192,7 @@ STATIC mp_obj_t machine_info(size_t n_args, const mp_obj_t *args) { break; } } + #endif } #if MICROPY_PY_THREAD diff --git a/ports/stm32/moduos.c b/ports/stm32/moduos.c index 5728f9c61c..0dde844f30 100644 --- a/ports/stm32/moduos.c +++ b/ports/stm32/moduos.c @@ -82,10 +82,12 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname); /// \function sync() /// Sync all filesystems. STATIC mp_obj_t os_sync(void) { + #if MICROPY_VFS_FAT for (mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) { // this assumes that vfs->obj is fs_user_mount_t with block device functions disk_ioctl(MP_OBJ_TO_PTR(vfs->obj), CTRL_SYNC, NULL); } + #endif return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(mod_os_sync_obj, os_sync); @@ -148,7 +150,9 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&uos_dupterm_obj) }, { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) }, + #if MICROPY_VFS_FAT { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table); diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 84e4892976..7bd9442131 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -76,7 +76,9 @@ #define MICROPY_ENABLE_SCHEDULER (1) #define MICROPY_SCHEDULER_DEPTH (8) #define MICROPY_VFS (1) +#ifndef MICROPY_VFS_FAT #define MICROPY_VFS_FAT (1) +#endif // control over Python builtins #define MICROPY_PY_FUNCTION_ATTRS (1) @@ -103,7 +105,7 @@ #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) #define MICROPY_PY_CMATH (1) #define MICROPY_PY_IO (1) -#define MICROPY_PY_IO_FILEIO (1) +#define MICROPY_PY_IO_FILEIO (MICROPY_VFS_FAT) // because mp_type_fileio/textio point to fatfs impl #define MICROPY_PY_SYS_MAXSIZE (1) #define MICROPY_PY_SYS_EXIT (1) #define MICROPY_PY_SYS_STDFILES (1) From 191e2cf90a948fd579b93de9a32800e82e1efcc0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 28 May 2018 21:44:42 +1000 Subject: [PATCH 726/828] lib/stm32lib: Update library to include support for STM32F0 MCUs. Now points to branch: work-F0-1.9.0+F4-1.16.0+F7-1.7.0+H7-1.2.0+L4-1.8.1 --- lib/stm32lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/stm32lib b/lib/stm32lib index 90b9961963..1fe30d1446 160000 --- a/lib/stm32lib +++ b/lib/stm32lib @@ -1 +1 @@ -Subproject commit 90b9961963b625db0f2aabfe8e5e508b1f4fb7f1 +Subproject commit 1fe30d1446f2eba3730dc4b05e9ac0cf03bcf9bf From 4a7d157a5b8aef4f4f433b3b1db01e8007008c9d Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 28 May 2018 18:14:37 +1000 Subject: [PATCH 727/828] stm32/boards: Add startup_stm32f0.s for STM32F0 MCUs. Sourced from STM32Cube_FW_F0_V1.9.0. --- ports/stm32/boards/startup_stm32f0.s | 303 +++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 ports/stm32/boards/startup_stm32f0.s diff --git a/ports/stm32/boards/startup_stm32f0.s b/ports/stm32/boards/startup_stm32f0.s new file mode 100644 index 0000000000..eb5c4961e0 --- /dev/null +++ b/ports/stm32/boards/startup_stm32f0.s @@ -0,0 +1,303 @@ +/** + ****************************************************************************** + * @file startup_stm32f091xc.s + * @author MCD Application Team + * @brief STM32F091xC devices vector table for GCC toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M0 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m0 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr r0, =_estack + mov sp, r0 /* set stack pointer */ + +/* Copy the data segment initializers from flash to SRAM */ + ldr r0, =_sdata + ldr r1, =_edata + ldr r2, =_sidata + movs r3, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r4, [r2, r3] + str r4, [r0, r3] + adds r3, r3, #4 + +LoopCopyDataInit: + adds r4, r0, r3 + cmp r4, r1 + bcc CopyDataInit + +/* Zero fill the bss segment. */ + ldr r2, =_sbss + ldr r4, =_ebss + movs r3, #0 + b LoopFillZerobss + +FillZerobss: + str r3, [r2] + adds r2, r2, #4 + +LoopFillZerobss: + cmp r2, r4 + bcc FillZerobss + +/* Call the clock system intitialization function.*/ + bl SystemInit +/* Call static constructors */ + /*bl __libc_init_array*/ +/* Call the application's entry point.*/ + bl main + +LoopForever: + b LoopForever + + +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * + * @param None + * @retval : None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex M0. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word 0 + .word 0 + .word PendSV_Handler + .word SysTick_Handler + .word WWDG_IRQHandler /* Window WatchDog */ + .word PVD_VDDIO2_IRQHandler /* PVD and VDDIO2 through EXTI Line detect */ + .word RTC_IRQHandler /* RTC through the EXTI line */ + .word FLASH_IRQHandler /* FLASH */ + .word RCC_CRS_IRQHandler /* RCC and CRS */ + .word EXTI0_1_IRQHandler /* EXTI Line 0 and 1 */ + .word EXTI2_3_IRQHandler /* EXTI Line 2 and 3 */ + .word EXTI4_15_IRQHandler /* EXTI Line 4 to 15 */ + .word TSC_IRQHandler /* TSC */ + .word DMA1_Ch1_IRQHandler /* DMA1 Channel 1 */ + .word DMA1_Ch2_3_DMA2_Ch1_2_IRQHandler /* DMA1 Channel 2 and 3 & DMA2 Channel 1 and 2 */ + .word DMA1_Ch4_7_DMA2_Ch3_5_IRQHandler /* DMA1 Channel 4 to 7 & DMA2 Channel 3 to 5 */ + .word ADC1_COMP_IRQHandler /* ADC1, COMP1 and COMP2 */ + .word TIM1_BRK_UP_TRG_COM_IRQHandler /* TIM1 Break, Update, Trigger and Commutation */ + .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ + .word TIM2_IRQHandler /* TIM2 */ + .word TIM3_IRQHandler /* TIM3 */ + .word TIM6_DAC_IRQHandler /* TIM6 and DAC */ + .word TIM7_IRQHandler /* TIM7 */ + .word TIM14_IRQHandler /* TIM14 */ + .word TIM15_IRQHandler /* TIM15 */ + .word TIM16_IRQHandler /* TIM16 */ + .word TIM17_IRQHandler /* TIM17 */ + .word I2C1_IRQHandler /* I2C1 */ + .word I2C2_IRQHandler /* I2C2 */ + .word SPI1_IRQHandler /* SPI1 */ + .word SPI2_IRQHandler /* SPI2 */ + .word USART1_IRQHandler /* USART1 */ + .word USART2_IRQHandler /* USART2 */ + .word USART3_8_IRQHandler /* USART3, USART4, USART5, USART6, USART7, USART8 */ + .word CEC_CAN_IRQHandler /* CEC and CAN */ + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_VDDIO2_IRQHandler + .thumb_set PVD_VDDIO2_IRQHandler,Default_Handler + + .weak RTC_IRQHandler + .thumb_set RTC_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_CRS_IRQHandler + .thumb_set RCC_CRS_IRQHandler,Default_Handler + + .weak EXTI0_1_IRQHandler + .thumb_set EXTI0_1_IRQHandler,Default_Handler + + .weak EXTI2_3_IRQHandler + .thumb_set EXTI2_3_IRQHandler,Default_Handler + + .weak EXTI4_15_IRQHandler + .thumb_set EXTI4_15_IRQHandler,Default_Handler + + .weak TSC_IRQHandler + .thumb_set TSC_IRQHandler,Default_Handler + + .weak DMA1_Ch1_IRQHandler + .thumb_set DMA1_Ch1_IRQHandler,Default_Handler + + .weak DMA1_Ch2_3_DMA2_Ch1_2_IRQHandler + .thumb_set DMA1_Ch2_3_DMA2_Ch1_2_IRQHandler,Default_Handler + + .weak DMA1_Ch4_7_DMA2_Ch3_5_IRQHandler + .thumb_set DMA1_Ch4_7_DMA2_Ch3_5_IRQHandler,Default_Handler + + .weak ADC1_COMP_IRQHandler + .thumb_set ADC1_COMP_IRQHandler,Default_Handler + + .weak TIM1_BRK_UP_TRG_COM_IRQHandler + .thumb_set TIM1_BRK_UP_TRG_COM_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + + .weak TIM14_IRQHandler + .thumb_set TIM14_IRQHandler,Default_Handler + + .weak TIM15_IRQHandler + .thumb_set TIM15_IRQHandler,Default_Handler + + .weak TIM16_IRQHandler + .thumb_set TIM16_IRQHandler,Default_Handler + + .weak TIM17_IRQHandler + .thumb_set TIM17_IRQHandler,Default_Handler + + .weak I2C1_IRQHandler + .thumb_set I2C1_IRQHandler,Default_Handler + + .weak I2C2_IRQHandler + .thumb_set I2C2_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + + .weak USART3_8_IRQHandler + .thumb_set USART3_8_IRQHandler,Default_Handler + + .weak CEC_CAN_IRQHandler + .thumb_set CEC_CAN_IRQHandler,Default_Handler + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + From ea7e747979c2f27eb90f9a6ba292c500eb288dd4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 28 May 2018 18:10:53 +1000 Subject: [PATCH 728/828] stm32: Add support for STM32F0 MCUs. --- ports/stm32/Makefile | 30 ++++- ports/stm32/adc.c | 34 +++-- ports/stm32/dac.c | 2 +- ports/stm32/dma.c | 57 +++++++- ports/stm32/dma.h | 2 +- ports/stm32/extint.c | 11 +- ports/stm32/flash.c | 15 ++- ports/stm32/i2c.c | 4 +- ports/stm32/machine_i2c.c | 2 +- ports/stm32/modmachine.c | 47 +++++-- ports/stm32/mpconfigboard_common.h | 10 +- ports/stm32/mphalport.c | 5 +- ports/stm32/rtc.c | 4 + ports/stm32/spi.c | 10 ++ ports/stm32/stm32_it.c | 50 +++++++ ports/stm32/system_stm32f0.c | 203 +++++++++++++++++++++++++++++ ports/stm32/timer.c | 20 ++- ports/stm32/uart.c | 20 ++- 18 files changed, 478 insertions(+), 48 deletions(-) create mode 100644 ports/stm32/system_stm32f0.c diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index cbfd8baa1a..afb21b048c 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -57,10 +57,15 @@ CFLAGS_CORTEX_M = -mthumb ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F767xx STM32F769xx STM32H743xx)) CFLAGS_CORTEX_M += -mfpu=fpv5-d16 -mfloat-abi=hard else +ifeq ($(MCU_SERIES),f0) +CFLAGS_CORTEX_M += -msoft-float +else CFLAGS_CORTEX_M += -mfpu=fpv4-sp-d16 -mfloat-abi=hard endif +endif # Options for particular MCU series +CFLAGS_MCU_f0 = $(CFLAGS_CORTEX_M) -mtune=cortex-m0 -mcpu=cortex-m0 CFLAGS_MCU_f4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 @@ -155,7 +160,6 @@ SRC_LIBM = $(addprefix lib/libm_dbl/,\ else SRC_LIBM = $(addprefix lib/libm/,\ math.c \ - thumb_vfp_sqrtf.c \ acoshf.c \ asinfacosf.c \ asinhf.c \ @@ -181,6 +185,11 @@ SRC_LIBM = $(addprefix lib/libm/,\ wf_lgamma.c \ wf_tgamma.c \ ) +ifeq ($(MCU_SERIES),f0) +SRC_LIBM += lib/libm/ef_sqrt.c +else +SRC_LIBM += lib/libm/thumb_vfp_sqrtf.c +endif endif EXTMOD_SRC_C = $(addprefix extmod/,\ @@ -197,7 +206,6 @@ DRIVERS_SRC_C = $(addprefix drivers/,\ SRC_C = \ main.c \ - system_stm32.c \ stm32_it.c \ usbd_conf.c \ usbd_desc.c \ @@ -252,10 +260,19 @@ SRC_C = \ adc.c \ $(wildcard boards/$(BOARD)/*.c) +ifeq ($(MCU_SERIES),f0) SRC_O = \ $(STARTUP_FILE) \ + system_stm32f0.o \ + resethandler_m0.o \ + gchelper_m0.o +else +SRC_O = \ + $(STARTUP_FILE) \ + system_stm32.o \ resethandler.o \ - gchelper.o \ + gchelper.o +endif SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ hal.c \ @@ -277,14 +294,19 @@ SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ hal_rcc_ex.c \ hal_rtc.c \ hal_rtc_ex.c \ - hal_sd.c \ hal_spi.c \ hal_tim.c \ hal_tim_ex.c \ hal_uart.c \ + ) + +ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h7 l4)) +SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ + hal_sd.c \ ll_sdmmc.c \ ll_usb.c \ ) +endif ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32H743xx)) SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_fdcan.c) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 773cccd40e..f439503e61 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -59,7 +59,15 @@ #define ADCx_CLK_ENABLE __HAL_RCC_ADC1_CLK_ENABLE #define ADC_NUM_CHANNELS (19) -#if defined(STM32F4) +#if defined(STM32F0) + +#define ADC_FIRST_GPIO_CHANNEL (0) +#define ADC_LAST_GPIO_CHANNEL (15) +#define ADC_CAL_ADDRESS (0x1ffff7ba) +#define ADC_CAL1 ((uint16_t*)0x1ffff7b8) +#define ADC_CAL2 ((uint16_t*)0x1ffff7c2) + +#elif defined(STM32F4) #define ADC_FIRST_GPIO_CHANNEL (0) #define ADC_LAST_GPIO_CHANNEL (15) @@ -104,7 +112,9 @@ #endif -#if defined(STM32F405xx) || defined(STM32F415xx) || \ +#if defined(STM32F091xC) +#define VBAT_DIV (2) +#elif defined(STM32F405xx) || defined(STM32F415xx) || \ defined(STM32F407xx) || defined(STM32F417xx) || \ defined(STM32F401xC) || defined(STM32F401xE) || \ defined(STM32F411xE) @@ -159,7 +169,7 @@ STATIC bool is_adcx_channel(int channel) { #if defined(STM32F411xE) // The HAL has an incorrect IS_ADC_CHANNEL macro for the F411 so we check for temp return IS_ADC_CHANNEL(channel) || channel == ADC_CHANNEL_TEMPSENSOR; -#elif defined(STM32F4) || defined(STM32F7) || defined(STM32H7) +#elif defined(STM32F0) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7) return IS_ADC_CHANNEL(channel); #elif defined(STM32L4) ADC_HandleTypeDef handle; @@ -174,7 +184,7 @@ STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) { uint32_t tickstart = HAL_GetTick(); #if defined(STM32F4) || defined(STM32F7) while ((ADCx->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC) { -#elif defined(STM32H7) || defined(STM32L4) +#elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4) while (READ_BIT(ADCx->ISR, ADC_FLAG_EOC) != ADC_FLAG_EOC) { #else #error Unsupported processor @@ -186,7 +196,7 @@ STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) { } STATIC void adcx_clock_enable(void) { -#if defined(STM32F4) || defined(STM32F7) +#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) ADCx_CLK_ENABLE(); #elif defined(STM32H7) __HAL_RCC_ADC3_CLK_ENABLE(); @@ -205,12 +215,14 @@ STATIC void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) { adch->Init.Resolution = resolution; adch->Init.ContinuousConvMode = DISABLE; adch->Init.DiscontinuousConvMode = DISABLE; + #if !defined(STM32F0) adch->Init.NbrOfDiscConversion = 0; adch->Init.NbrOfConversion = 1; + #endif adch->Init.EOCSelection = ADC_EOC_SINGLE_CONV; adch->Init.ExternalTrigConv = ADC_SOFTWARE_START; adch->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; - #if defined(STM32F4) || defined(STM32F7) + #if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) adch->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; adch->Init.ScanConvMode = DISABLE; adch->Init.DataAlign = ADC_DATAALIGN_RIGHT; @@ -271,7 +283,9 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) sConfig.Channel = channel; sConfig.Rank = 1; -#if defined(STM32F4) || defined(STM32F7) +#if defined(STM32F0) + sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES_5; +#elif defined(STM32F4) || defined(STM32F7) sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES; #elif defined(STM32H7) sConfig.SamplingTime = ADC_SAMPLETIME_8CYCLES_5; @@ -283,10 +297,10 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5; sConfig.SingleDiff = ADC_SINGLE_ENDED; sConfig.OffsetNumber = ADC_OFFSET_NONE; + sConfig.Offset = 0; #else #error Unsupported processor #endif - sConfig.Offset = 0; HAL_ADC_ConfigChannel(adc_handle, &sConfig); } @@ -443,7 +457,7 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_ // for subsequent samples we can just set the "start sample" bit #if defined(STM32F4) || defined(STM32F7) ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART; -#elif defined(STM32H7) || defined(STM32L4) +#elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4) SET_BIT(ADCx->CR, ADC_CR_ADSTART); #else #error Unsupported processor @@ -553,7 +567,7 @@ STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_i // ADC is started: set the "start sample" bit #if defined(STM32F4) || defined(STM32F7) ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART; - #elif defined(STM32H7) || defined(STM32L4) + #elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4) SET_BIT(ADCx->CR, ADC_CR_ADSTART); #else #error Unsupported processor diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c index 0c9e0ae0cf..559bb0b0d0 100644 --- a/ports/stm32/dac.c +++ b/ports/stm32/dac.c @@ -177,7 +177,7 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp __DAC_CLK_ENABLE(); #elif defined(STM32H7) __HAL_RCC_DAC12_CLK_ENABLE(); - #elif defined(STM32L4) + #elif defined(STM32F0) || defined(STM32L4) __HAL_RCC_DAC1_CLK_ENABLE(); #else #error Unsupported Processor diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index 499649b36d..dc1ad6c1cd 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -55,7 +55,7 @@ typedef enum { struct _dma_descr_t { #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) DMA_Stream_TypeDef *instance; - #elif defined(STM32L4) + #elif defined(STM32F0) || defined(STM32L4) DMA_Channel_TypeDef *instance; #else #error "Unsupported Processor" @@ -141,7 +141,46 @@ static const DMA_InitTypeDef dma_init_struct_dac = { }; #endif -#if defined(STM32F4) || defined(STM32F7) +#if defined(STM32F0) + +#define NCONTROLLERS (2) +#define NSTREAMS_PER_CONTROLLER (7) +#define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER) + +#define DMA_SUB_INSTANCE_AS_UINT8(dma_channel) (dma_channel) + +#define DMA1_ENABLE_MASK (0x007f) // Bits in dma_enable_mask corresponfing to DMA1 (7 channels) +#define DMA2_ENABLE_MASK (0x0f80) // Bits in dma_enable_mask corresponding to DMA2 (only 5 channels) + +// DMA1 streams +#if MICROPY_HW_ENABLE_DAC +const dma_descr_t dma_DAC_1_TX = { DMA1_Channel3, HAL_DMA1_CH3_DAC_CH1, DMA_MEMORY_TO_PERIPH, dma_id_3, &dma_init_struct_dac }; +const dma_descr_t dma_DAC_2_TX = { DMA1_Channel4, HAL_DMA1_CH4_DAC_CH2, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_dac }; +#endif +const dma_descr_t dma_SPI_2_TX = { DMA1_Channel5, HAL_DMA1_CH5_SPI2_TX, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_spi_i2c}; +const dma_descr_t dma_SPI_2_RX = { DMA1_Channel6, HAL_DMA1_CH6_SPI2_RX, DMA_PERIPH_TO_MEMORY, dma_id_6, &dma_init_struct_spi_i2c}; +const dma_descr_t dma_SPI_1_RX = { DMA2_Channel3, HAL_DMA2_CH3_SPI1_RX, DMA_PERIPH_TO_MEMORY, dma_id_3, &dma_init_struct_spi_i2c}; +const dma_descr_t dma_SPI_1_TX = { DMA2_Channel4, HAL_DMA2_CH4_SPI1_TX, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c}; + +static const uint8_t dma_irqn[NSTREAM] = { + DMA1_Ch1_IRQn, + DMA1_Ch2_3_DMA2_Ch1_2_IRQn, + DMA1_Ch2_3_DMA2_Ch1_2_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + + DMA1_Ch2_3_DMA2_Ch1_2_IRQn, + DMA1_Ch2_3_DMA2_Ch1_2_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + 0, + 0, +}; + +#elif defined(STM32F4) || defined(STM32F7) #define NCONTROLLERS (2) #define NSTREAMS_PER_CONTROLLER (8) @@ -381,8 +420,13 @@ volatile dma_idle_count_t dma_idle; #define DMA_INVALID_CHANNEL 0xff // Value stored in dma_last_channel which means invalid +#if defined(STM32F0) +#define DMA1_IS_CLK_ENABLED() ((RCC->AHBENR & RCC_AHBENR_DMA1EN) != 0) +#define DMA2_IS_CLK_ENABLED() ((RCC->AHBENR & RCC_AHBENR_DMA2EN) != 0) +#else #define DMA1_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA1EN) != 0) #define DMA2_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA2EN) != 0) +#endif #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) @@ -476,8 +520,10 @@ void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void #if defined(STM32L4) || defined(STM32H7) dma->Init.Request = dma_descr->sub_instance; #else + #if !defined(STM32F0) dma->Init.Channel = dma_descr->sub_instance; #endif + #endif // half of __HAL_LINKDMA(data, xxx, *dma) // caller must implement other half by doing: data->xxx = dma dma->Parent = data; @@ -517,6 +563,13 @@ void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void *data){ HAL_DMA_DeInit(dma); HAL_DMA_Init(dma); NVIC_SetPriority(IRQn_NONNEG(dma_irqn[dma_id]), IRQ_PRI_DMA); + #if defined(STM32F0) + if (dma->Instance < DMA2_Channel1) { + __HAL_DMA1_REMAP(dma_descr->sub_instance); + } else { + __HAL_DMA2_REMAP(dma_descr->sub_instance); + } + #endif } else { // only necessary initialization dma->State = HAL_DMA_STATE_READY; diff --git a/ports/stm32/dma.h b/ports/stm32/dma.h index f265d60357..cacabe9253 100644 --- a/ports/stm32/dma.h +++ b/ports/stm32/dma.h @@ -28,7 +28,7 @@ typedef struct _dma_descr_t dma_descr_t; -#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) +#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7) extern const dma_descr_t dma_I2C_1_RX; extern const dma_descr_t dma_SPI_3_RX; diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c index 844cfb0622..70bf7eae7e 100644 --- a/ports/stm32/extint.c +++ b/ports/stm32/extint.c @@ -133,6 +133,12 @@ STATIC mp_obj_t pyb_extint_callback_arg[EXTI_NUM_VECTORS]; #endif STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = { + #if defined(STM32F0) + EXTI0_1_IRQn, EXTI0_1_IRQn, EXTI2_3_IRQn, EXTI2_3_IRQn, + EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, + EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, + EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, + #else EXTI0_IRQn, EXTI1_IRQn, EXTI2_IRQn, EXTI3_IRQn, EXTI4_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, @@ -148,6 +154,7 @@ STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = { OTG_HS_WKUP_IRQn, TAMP_STAMP_IRQn, RTC_WKUP_IRQn, + #endif }; // Set override_callback_obj to true if you want to unconditionally set the @@ -282,7 +289,7 @@ void extint_enable(uint line) { if (line >= EXTI_NUM_VECTORS) { return; } - #if defined(STM32F7) || defined(STM32H7) + #if defined(STM32F0) || defined(STM32F7) || defined(STM32H7) // The Cortex-M7 doesn't have bitband support. mp_uint_t irq_state = disable_irq(); if (pyb_extint_mode[line] == EXTI_Mode_Interrupt) { @@ -312,7 +319,7 @@ void extint_disable(uint line) { return; } - #if defined(STM32F7) || defined(STM32H7) + #if defined(STM32F0) || defined(STM32F7) || defined(STM32H7) // The Cortex-M7 doesn't have bitband support. mp_uint_t irq_state = disable_irq(); #if defined(STM32H7) diff --git a/ports/stm32/flash.c b/ports/stm32/flash.c index bc5b3c60c2..d3a568858c 100644 --- a/ports/stm32/flash.c +++ b/ports/stm32/flash.c @@ -34,7 +34,13 @@ typedef struct { uint32_t sector_count; } flash_layout_t; -#if defined(STM32F4) +#if defined(STM32F0) + +static const flash_layout_t flash_layout[] = { + { FLASH_BASE, FLASH_PAGE_SIZE, (FLASH_BANK1_END + 1 - FLASH_BASE) / FLASH_PAGE_SIZE }, +}; + +#elif defined(STM32F4) static const flash_layout_t flash_layout[] = { { 0x08000000, 0x04000, 4 }, @@ -153,7 +159,12 @@ void flash_erase(uint32_t flash_dest, uint32_t num_word32) { FLASH_EraseInitTypeDef EraseInitStruct; - #if defined(STM32L4) + #if defined(STM32F0) + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR); + EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; + EraseInitStruct.PageAddress = flash_dest; + EraseInitStruct.NbPages = (4 * num_word32 + FLASH_PAGE_SIZE - 4) / FLASH_PAGE_SIZE; + #elif defined(STM32L4) __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS); // erase the sector(s) diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index a717ca7b39..e0eea90ab7 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -262,7 +262,7 @@ int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len) { return num_acks; } -#elif defined(STM32F7) +#elif defined(STM32F0) || defined(STM32F7) int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t freq) { uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); @@ -446,7 +446,7 @@ int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len) { #endif -#if defined(STM32F4) || defined(STM32F7) +#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) int i2c_readfrom(i2c_t *i2c, uint16_t addr, uint8_t *dest, size_t len, bool stop) { int ret; diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c index 4cb1dc97d6..b7a9ea69bf 100644 --- a/ports/stm32/machine_i2c.c +++ b/ports/stm32/machine_i2c.c @@ -37,7 +37,7 @@ STATIC const mp_obj_type_t machine_hard_i2c_type; -#if defined(STM32F4) || defined(STM32F7) +#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) typedef struct _machine_hard_i2c_obj_t { mp_obj_base_t base; diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index d8054c3f25..158f5f2b34 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -110,7 +110,11 @@ void machine_init(void) { uint32_t state = RCC->RCC_SR; if (state & RCC_SR_IWDGRSTF || state & RCC_SR_WWDGRSTF) { reset_cause = PYB_RESET_WDT; - } else if (state & RCC_SR_PORRSTF || state & RCC_SR_BORRSTF) { + } else if (state & RCC_SR_PORRSTF + #if !defined(STM32F0) + || state & RCC_SR_BORRSTF + #endif + ) { reset_cause = PYB_RESET_POWER_ON; } else if (state & RCC_SR_PINRSTF) { reset_cause = PYB_RESET_HARD; @@ -140,11 +144,18 @@ STATIC mp_obj_t machine_info(size_t n_args, const mp_obj_t *args) { // get and print clock speeds // SYSCLK=168MHz, HCLK=168MHz, PCLK1=42MHz, PCLK2=84MHz { + #if defined(STM32F0) + printf("S=%u\nH=%u\nP1=%u\n", + (unsigned int)HAL_RCC_GetSysClockFreq(), + (unsigned int)HAL_RCC_GetHCLKFreq(), + (unsigned int)HAL_RCC_GetPCLK1Freq()); + #else printf("S=%u\nH=%u\nP1=%u\nP2=%u\n", (unsigned int)HAL_RCC_GetSysClockFreq(), (unsigned int)HAL_RCC_GetHCLKFreq(), (unsigned int)HAL_RCC_GetPCLK1Freq(), (unsigned int)HAL_RCC_GetPCLK2Freq()); + #endif } // to print info about memory @@ -267,6 +278,7 @@ STATIC NORETURN mp_obj_t machine_bootloader(void) { } MP_DEFINE_CONST_FUN_OBJ_0(machine_bootloader_obj, machine_bootloader); +#if !(defined(STM32F0) || defined(STM32L4)) // get or set the MCU frequencies STATIC mp_uint_t machine_freq_calc_ahb_div(mp_uint_t wanted_div) { if (wanted_div <= 1) { return RCC_SYSCLK_DIV1; } @@ -286,23 +298,28 @@ STATIC mp_uint_t machine_freq_calc_apb_div(mp_uint_t wanted_div) { else if (wanted_div <= 8) { return RCC_HCLK_DIV8; } else { return RCC_SYSCLK_DIV16; } } +#endif + STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { if (n_args == 0) { // get - mp_obj_t tuple[4] = { + mp_obj_t tuple[] = { mp_obj_new_int(HAL_RCC_GetSysClockFreq()), mp_obj_new_int(HAL_RCC_GetHCLKFreq()), mp_obj_new_int(HAL_RCC_GetPCLK1Freq()), + #if !defined(STM32F0) mp_obj_new_int(HAL_RCC_GetPCLK2Freq()), + #endif }; - return mp_obj_new_tuple(4, tuple); + return mp_obj_new_tuple(MP_ARRAY_SIZE(tuple), tuple); } else { // set - mp_int_t wanted_sysclk = mp_obj_get_int(args[0]) / 1000000; - #if defined(STM32L4) + #if defined(STM32F0) || defined(STM32L4) mp_raise_NotImplementedError("machine.freq set not supported yet"); - #endif + #else + + mp_int_t wanted_sysclk = mp_obj_get_int(args[0]) / 1000000; // default PLL parameters that give 48MHz on PLL48CK uint32_t m = HSE_VALUE / 1000000, n = 336, p = 2, q = 7; @@ -458,6 +475,8 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { fail:; void NORETURN __fatal_error(const char *msg); __fatal_error("can't change freq"); + + #endif } } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 4, machine_freq); @@ -492,8 +511,10 @@ STATIC mp_obj_t machine_sleep(void) { #else + #if !defined(STM32F0) // takes longer to wake but reduces stop current HAL_PWREx_EnableFlashPowerDown(); + #endif # if defined(STM32F7) HAL_PWR_EnterSTOPMode((PWR_CR1_LPDS | PWR_CR1_LPUDS | PWR_CR1_FPDS | PWR_CR1_UDEN), PWR_STOPENTRY_WFI); @@ -542,16 +563,22 @@ STATIC mp_obj_t machine_deepsleep(void) { // Note: we only support RTC ALRA, ALRB, WUT and TS. // TODO support TAMP and WKUP (PA0 external pin). - uint32_t irq_bits = RTC_CR_ALRAIE | RTC_CR_ALRBIE | RTC_CR_WUTIE | RTC_CR_TSIE; + #if defined(STM32F0) + #define CR_BITS (RTC_CR_ALRAIE | RTC_CR_WUTIE | RTC_CR_TSIE) + #define ISR_BITS (RTC_ISR_ALRAF | RTC_ISR_WUTF | RTC_ISR_TSF) + #else + #define CR_BITS (RTC_CR_ALRAIE | RTC_CR_ALRBIE | RTC_CR_WUTIE | RTC_CR_TSIE) + #define ISR_BITS (RTC_ISR_ALRAF | RTC_ISR_ALRBF | RTC_ISR_WUTF | RTC_ISR_TSF) + #endif // save RTC interrupts - uint32_t save_irq_bits = RTC->CR & irq_bits; + uint32_t save_irq_bits = RTC->CR & CR_BITS; // disable RTC interrupts - RTC->CR &= ~irq_bits; + RTC->CR &= ~CR_BITS; // clear RTC wake-up flags - RTC->ISR &= ~(RTC_ISR_ALRAF | RTC_ISR_ALRBF | RTC_ISR_WUTF | RTC_ISR_TSF); + RTC->ISR &= ~ISR_BITS; #if defined(STM32F7) // disable wake-up flags diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 919598de44..2cc02b77cf 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -110,8 +110,16 @@ /*****************************************************************************/ // General configuration +// Configuration for STM32F0 series +#if defined(STM32F0) + +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ffff7ac) +#define PYB_EXTI_NUM_VECTORS (23) +#define MICROPY_HW_MAX_TIMER (17) +#define MICROPY_HW_MAX_UART (8) + // Configuration for STM32F4 series -#if defined(STM32F4) +#elif defined(STM32F4) #define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7a10) #define PYB_EXTI_NUM_VECTORS (23) diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c index 2bf10ad479..a2f8e412ee 100644 --- a/ports/stm32/mphalport.c +++ b/ports/stm32/mphalport.c @@ -111,7 +111,10 @@ void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) { // This logic assumes that all the GPIOx_EN bits are adjacent and ordered in one register - #if defined(STM32F4) || defined(STM32F7) + #if defined(STM32F0) + #define AHBxENR AHBENR + #define AHBxENR_GPIOAEN_Pos RCC_AHBENR_GPIOAEN_Pos + #elif defined(STM32F4) || defined(STM32F7) #define AHBxENR AHB1ENR #define AHBxENR_GPIOAEN_Pos RCC_AHB1ENR_GPIOAEN_Pos #elif defined(STM32H7) diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index 4134037124..c51dfab119 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -539,6 +539,10 @@ mp_obj_t pyb_rtc_datetime(size_t n_args, const mp_obj_t *args) { } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_datetime_obj, 1, 2, pyb_rtc_datetime); +#if defined(STM32F0) +#define RTC_WKUP_IRQn RTC_IRQn +#endif + // wakeup(None) // wakeup(ms, callback=None) // wakeup(wucksel, wut, callback) diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c index a6e7143171..c578ac7da2 100644 --- a/ports/stm32/spi.c +++ b/ports/stm32/spi.c @@ -203,6 +203,9 @@ STATIC void spi_set_params(const spi_t *spi_obj, uint32_t prescale, int32_t baud if (prescale == 0xffffffff) { // prescaler not given, so select one that yields at most the requested baudrate mp_uint_t spi_clock; + #if defined(STM32F0) + spi_clock = HAL_RCC_GetPCLK1Freq(); + #else if (spi->Instance == SPI2 || spi->Instance == SPI3) { // SPI2 and SPI3 are on APB1 spi_clock = HAL_RCC_GetPCLK1Freq(); @@ -210,6 +213,7 @@ STATIC void spi_set_params(const spi_t *spi_obj, uint32_t prescale, int32_t baud // SPI1, SPI4, SPI5 and SPI6 are on APB2 spi_clock = HAL_RCC_GetPCLK2Freq(); } + #endif prescale = spi_clock / baudrate; } if (prescale <= 2) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; } @@ -500,7 +504,9 @@ STATIC void spi_print(const mp_print_t *print, const spi_t *spi_obj, bool legacy uint spi_num = 1; // default to SPI1 if (spi->Instance == SPI2) { spi_num = 2; } + #if defined(SPI3) else if (spi->Instance == SPI3) { spi_num = 3; } + #endif #if defined(SPI4) else if (spi->Instance == SPI4) { spi_num = 4; } #endif @@ -516,6 +522,9 @@ STATIC void spi_print(const mp_print_t *print, const spi_t *spi_obj, bool legacy if (spi->Init.Mode == SPI_MODE_MASTER) { // compute baudrate uint spi_clock; + #if defined(STM32F0) + spi_clock = HAL_RCC_GetPCLK1Freq(); + #else if (spi->Instance == SPI2 || spi->Instance == SPI3) { // SPI2 and SPI3 are on APB1 spi_clock = HAL_RCC_GetPCLK1Freq(); @@ -523,6 +532,7 @@ STATIC void spi_print(const mp_print_t *print, const spi_t *spi_obj, bool legacy // SPI1, SPI4, SPI5 and SPI6 are on APB2 spi_clock = HAL_RCC_GetPCLK2Freq(); } + #endif uint log_prescaler = (spi->Init.BaudRatePrescaler >> 3) + 1; uint baudrate = spi_clock >> log_prescaler; if (legacy) { diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 8202209775..c09ffce767 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -579,6 +579,39 @@ void RTC_WKUP_IRQHandler(void) { IRQ_EXIT(RTC_WKUP_IRQn); } +#if defined(STM32F0) + +void RTC_IRQHandler(void) { + IRQ_ENTER(RTC_IRQn); + RTC->ISR &= ~(1 << 10); // clear wakeup interrupt flag + Handle_EXTI_Irq(EXTI_RTC_WAKEUP); // clear EXTI flag and execute optional callback + IRQ_EXIT(RTC_IRQn); +} + +void EXTI0_1_IRQHandler(void) { + IRQ_ENTER(EXTI0_1_IRQn); + Handle_EXTI_Irq(0); + Handle_EXTI_Irq(1); + IRQ_EXIT(EXTI0_1_IRQn); +} + +void EXTI2_3_IRQHandler(void) { + IRQ_ENTER(EXTI2_3_IRQn); + Handle_EXTI_Irq(2); + Handle_EXTI_Irq(3); + IRQ_EXIT(EXTI2_3_IRQn); +} + +void EXTI4_15_IRQHandler(void) { + IRQ_ENTER(EXTI4_15_IRQn); + for (int i = 4; i <= 15; ++i) { + Handle_EXTI_Irq(i); + } + IRQ_EXIT(EXTI4_15_IRQn); +} + +#endif + void TIM1_BRK_TIM9_IRQHandler(void) { IRQ_ENTER(TIM1_BRK_TIM9_IRQn); timer_irq_handler(9); @@ -718,6 +751,21 @@ void USART2_IRQHandler(void) { IRQ_EXIT(USART2_IRQn); } +#if defined(STM32F0) + +void USART3_8_IRQHandler(void) { + IRQ_ENTER(USART3_8_IRQn); + uart_irq_handler(3); + uart_irq_handler(4); + uart_irq_handler(5); + uart_irq_handler(6); + uart_irq_handler(7); + uart_irq_handler(8); + IRQ_EXIT(USART3_8_IRQn); +} + +#else + void USART3_IRQHandler(void) { IRQ_ENTER(USART3_IRQn); uart_irq_handler(3); @@ -758,6 +806,8 @@ void UART8_IRQHandler(void) { } #endif +#endif + #if defined(MICROPY_HW_CAN1_TX) void CAN1_RX0_IRQHandler(void) { IRQ_ENTER(CAN1_RX0_IRQn); diff --git a/ports/stm32/system_stm32f0.c b/ports/stm32/system_stm32f0.c new file mode 100644 index 0000000000..9d4b06e568 --- /dev/null +++ b/ports/stm32/system_stm32f0.c @@ -0,0 +1,203 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Taken from ST Cube library and modified. See below for original header. + */ + +/** + ****************************************************************************** + * @file system_stm32f0xx.c + * @author MCD Application Team + * @brief CMSIS Cortex-M0 Device Peripheral Access Layer System Source File. + * + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +#include STM32_HAL_H + +#ifndef HSE_VALUE +#define HSE_VALUE (8000000) +#endif + +#ifndef HSI_VALUE +#define HSI_VALUE (8000000) +#endif + +#ifndef HSI48_VALUE +#define HSI48_VALUE (48000000) +#endif + +/* This variable is updated in three ways: + 1) by calling CMSIS function SystemCoreClockUpdate() + 2) by calling HAL API function HAL_RCC_GetHCLKFreq() + 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency + Note: If you use this function to configure the system clock there is no need to + call the 2 first functions listed above, since SystemCoreClock variable is + updated automatically. +*/ +uint32_t SystemCoreClock = 8000000; + +const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; +const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; + +void SystemInit(void) { + // Set HSION bit + RCC->CR |= (uint32_t)0x00000001U; + + #if defined(STM32F051x8) || defined(STM32F058x8) + // Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE and MCOSEL[2:0] bits + RCC->CFGR &= (uint32_t)0xF8FFB80CU; + #else + // Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE, MCOSEL[2:0], MCOPRE[2:0] and PLLNODIV bits + RCC->CFGR &= (uint32_t)0x08FFB80CU; + #endif + + // Reset HSEON, CSSON and PLLON bits + RCC->CR &= (uint32_t)0xFEF6FFFFU; + + // Reset HSEBYP bit + RCC->CR &= (uint32_t)0xFFFBFFFFU; + + // Reset PLLSRC, PLLXTPRE and PLLMUL[3:0] bits + RCC->CFGR &= (uint32_t)0xFFC0FFFFU; + + // Reset PREDIV[3:0] bits + RCC->CFGR2 &= (uint32_t)0xFFFFFFF0U; + + #if defined(STM32F072xB) || defined(STM32F078xx) + // Reset USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW, USBSW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFFCFE2CU; + #elif defined(STM32F071xB) + // Reset USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFFFCEACU; + #elif defined(STM32F091xC) || defined(STM32F098xx) + // Reset USART3SW[1:0], USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFF0FEACU; + #elif defined(STM32F030x6) || defined(STM32F030x8) || defined(STM32F031x6) || defined(STM32F038xx) || defined(STM32F030xC) + // Reset USART1SW[1:0], I2C1SW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFFFFEECU; + #elif defined(STM32F051x8) || defined(STM32F058xx) + // Reset USART1SW[1:0], I2C1SW, CECSW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFFFFEACU; + #elif defined(STM32F042x6) || defined(STM32F048xx) + // Reset USART1SW[1:0], I2C1SW, CECSW, USBSW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFFFFE2CU; + #elif defined(STM32F070x6) || defined(STM32F070xB) + // Reset USART1SW[1:0], I2C1SW, USBSW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFFFFE6CU; + // Set default USB clock to PLLCLK, since there is no HSI48 + RCC->CFGR3 |= (uint32_t)0x00000080U; + #else + #warning "No target selected" + #endif + + // Reset HSI14 bit + RCC->CR2 &= (uint32_t)0xFFFFFFFEU; + + // Disable all interrupts + RCC->CIR = 0x00000000U; + + // dpgeorge: enable 8-byte stack alignment for IRQ handlers, in accord with EABI + SCB->CCR |= SCB_CCR_STKALIGN_Msk; +} + +void SystemClock_Config(void) { + // Set flash latency to 1 because SYSCLK > 24MHz + FLASH->ACR = (FLASH->ACR & ~0x7) | 0x1; + + // Use the 48MHz internal oscillator + RCC->CR2 |= RCC_CR2_HSI48ON; + while ((RCC->CR2 & RCC_CR2_HSI48RDY) == 0) { + } + RCC->CFGR |= 3 << RCC_CFGR_SW_Pos; + while (((RCC->CFGR >> RCC_CFGR_SWS_Pos) & 0x3) != 0x03) { + // Wait for SYSCLK source to change + } + + SystemCoreClockUpdate(); + + HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000); + HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); +} + +void SystemCoreClockUpdate(void) { + // Get SYSCLK source + uint32_t tmp = RCC->CFGR & RCC_CFGR_SWS; + + switch (tmp) { + case RCC_CFGR_SWS_HSI: + SystemCoreClock = HSI_VALUE; + break; + case RCC_CFGR_SWS_HSE: + SystemCoreClock = HSE_VALUE; + break; + case RCC_CFGR_SWS_PLL: { + /* Get PLL clock source and multiplication factor */ + uint32_t pllmull = RCC->CFGR & RCC_CFGR_PLLMUL; + uint32_t pllsource = RCC->CFGR & RCC_CFGR_PLLSRC; + pllmull = (pllmull >> 18) + 2; + uint32_t predivfactor = (RCC->CFGR2 & RCC_CFGR2_PREDIV) + 1; + + if (pllsource == RCC_CFGR_PLLSRC_HSE_PREDIV) { + /* HSE used as PLL clock source : SystemCoreClock = HSE/PREDIV * PLLMUL */ + SystemCoreClock = (HSE_VALUE/predivfactor) * pllmull; + #if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F072xB) \ + || defined(STM32F078xx) || defined(STM32F091xC) || defined(STM32F098xx) + } else if (pllsource == RCC_CFGR_PLLSRC_HSI48_PREDIV) { + /* HSI48 used as PLL clock source : SystemCoreClock = HSI48/PREDIV * PLLMUL */ + SystemCoreClock = (HSI48_VALUE/predivfactor) * pllmull; + #endif + } else { + #if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F070x6) \ + || defined(STM32F078xx) || defined(STM32F071xB) || defined(STM32F072xB) \ + || defined(STM32F070xB) || defined(STM32F091xC) || defined(STM32F098xx) || defined(STM32F030xC) + /* HSI used as PLL clock source : SystemCoreClock = HSI/PREDIV * PLLMUL */ + SystemCoreClock = (HSI_VALUE / predivfactor) * pllmull; + #else + /* HSI used as PLL clock source : SystemCoreClock = HSI/2 * PLLMUL */ + SystemCoreClock = (HSI_VALUE >> 1) * pllmull; + #endif + } + break; + } + case RCC_CFGR_SWS_HSI48: + SystemCoreClock = HSI48_VALUE; + break; + default: + SystemCoreClock = HSI_VALUE; + break; + } + + // Compute HCLK clock frequency + tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)]; + SystemCoreClock >>= tmp; +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c index fd719b2f2c..cc00f7a887 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -231,16 +231,22 @@ uint32_t timer_get_source_freq(uint32_t tim_id) { uint32_t source, clk_div; if (tim_id == 1 || (8 <= tim_id && tim_id <= 11)) { // TIM{1,8,9,10,11} are on APB2 + #if defined(STM32F0) + source = HAL_RCC_GetPCLK1Freq(); + clk_div = RCC->CFGR & RCC_CFGR_PPRE; + #elif defined(STM32H7) source = HAL_RCC_GetPCLK2Freq(); - #if defined(STM32H7) clk_div = RCC->D2CFGR & RCC_D2CFGR_D2PPRE2; #else + source = HAL_RCC_GetPCLK2Freq(); clk_div = RCC->CFGR & RCC_CFGR_PPRE2; #endif } else { // TIM{2,3,4,5,6,7,12,13,14} are on APB1 source = HAL_RCC_GetPCLK1Freq(); - #if defined(STM32H7) + #if defined(STM32F0) + clk_div = RCC->CFGR & RCC_CFGR_PPRE; + #elif defined(STM32H7) clk_div = RCC->D2CFGR & RCC_D2CFGR_D2PPRE1; #else clk_div = RCC->CFGR & RCC_CFGR_PPRE1; @@ -694,25 +700,27 @@ STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = { #if defined(TIM13) TIM_ENTRY(13, TIM8_UP_TIM13_IRQn), #endif - #if defined(TIM14) + #if defined(STM32F0) + TIM_ENTRY(14, TIM14_IRQn), + #elif defined(TIM14) TIM_ENTRY(14, TIM8_TRG_COM_TIM14_IRQn), #endif #if defined(TIM15) - #if defined(STM32H7) + #if defined(STM32F0) || defined(STM32H7) TIM_ENTRY(15, TIM15_IRQn), #else TIM_ENTRY(15, TIM1_BRK_TIM15_IRQn), #endif #endif #if defined(TIM16) - #if defined(STM32H7) + #if defined(STM32F0) || defined(STM32H7) TIM_ENTRY(16, TIM16_IRQn), #else TIM_ENTRY(16, TIM1_UP_TIM16_IRQn), #endif #endif #if defined(TIM17) - #if defined(STM32H7) + #if defined(STM32F0) || defined(STM32H7) TIM_ENTRY(17, TIM17_IRQn), #else TIM_ENTRY(17, TIM1_TRG_COM_TIM17_IRQn), diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index 54dcc05728..1622c505c1 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -289,11 +289,17 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { #if defined(MICROPY_HW_UART8_TX) && defined(MICROPY_HW_UART8_RX) case PYB_UART_8: uart_unit = 8; + #if defined(STM32F0) + UARTx = USART8; + irqn = USART3_8_IRQn; + __HAL_RCC_USART8_CLK_ENABLE(); + #else UARTx = UART8; irqn = UART8_IRQn; + __HAL_RCC_UART8_CLK_ENABLE(); + #endif pins[0] = MICROPY_HW_UART8_TX; pins[1] = MICROPY_HW_UART8_RX; - __HAL_RCC_UART8_CLK_ENABLE(); break; #endif @@ -390,7 +396,7 @@ int uart_rx_char(pyb_uart_obj_t *self) { return data; } else { // no buffering - #if defined(STM32F7) || defined(STM32L4) || defined(STM32H7) + #if defined(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7) return self->uart.Instance->RDR & self->char_mask; #else return self->uart.Instance->DR & self->char_mask; @@ -508,7 +514,7 @@ void uart_irq_handler(mp_uint_t uart_id) { uint16_t next_head = (self->read_buf_head + 1) % self->read_buf_len; if (next_head != self->read_buf_tail) { // only read data if room in buf - #if defined(STM32F7) || defined(STM32L4) || defined(STM32H7) + #if defined(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7) int data = self->uart.Instance->RDR; // clears UART_FLAG_RXNE #else int data = self->uart.Instance->DR; // clears UART_FLAG_RXNE @@ -698,7 +704,9 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const // compute actual baudrate that was configured // (this formula assumes UART_OVERSAMPLING_16) uint32_t actual_baudrate = 0; - #if defined(STM32F7) || defined(STM32H7) + #if defined(STM32F0) + actual_baudrate = HAL_RCC_GetPCLK1Freq(); + #elif defined(STM32F7) || defined(STM32H7) UART_ClockSourceTypeDef clocksource = UART_CLOCKSOURCE_UNDEFINED; UART_GETCLOCKSOURCE(&self->uart, clocksource); switch (clocksource) { @@ -854,7 +862,9 @@ STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) { __HAL_RCC_USART2_CLK_DISABLE(); #if defined(USART3) } else if (uart->Instance == USART3) { + #if !defined(STM32F0) HAL_NVIC_DisableIRQ(USART3_IRQn); + #endif __HAL_RCC_USART3_FORCE_RESET(); __HAL_RCC_USART3_RELEASE_RESET(); __HAL_RCC_USART3_CLK_DISABLE(); @@ -949,7 +959,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_readchar_obj, pyb_uart_readchar); // uart.sendbreak() STATIC mp_obj_t pyb_uart_sendbreak(mp_obj_t self_in) { pyb_uart_obj_t *self = self_in; - #if defined(STM32F7) || defined(STM32L4) || defined(STM32H7) + #if defined(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7) self->uart.Instance->RQR = USART_RQR_SBKRQ; // write-only register #else self->uart.Instance->CR1 |= USART_CR1_SBK; From 11634000393de1878b8225faded391fa196a2c65 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 28 May 2018 18:11:43 +1000 Subject: [PATCH 729/828] stm32/boards: Add alt-func CSV list and linker script for STM32F091. --- ports/stm32/boards/stm32f091_af.csv | 89 +++++++++++++++++++++++++++++ ports/stm32/boards/stm32f091xc.ld | 26 +++++++++ 2 files changed, 115 insertions(+) create mode 100644 ports/stm32/boards/stm32f091_af.csv create mode 100644 ports/stm32/boards/stm32f091xc.ld diff --git a/ports/stm32/boards/stm32f091_af.csv b/ports/stm32/boards/stm32f091_af.csv new file mode 100644 index 0000000000..c1ff5aaf29 --- /dev/null +++ b/ports/stm32/boards/stm32f091_af.csv @@ -0,0 +1,89 @@ +Port,Pin,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,,,,,,,,, +,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,,,,,,,,,ADC +PortA,PA0,,USART2_CTS,TIM2_CH1_ETR,TSC_G1_IO1,USART4_TX,,,COMP1_OUT,,,,,,,,,ADC1_IN0 +PortA,PA1,EVENTOUT,USART2_RTS,TIM2_CH2,TSC_G1_IO2,USART4_RX,TIM15_CH1N,,,,,,,,,,,ADC1_IN1 +PortA,PA2,TIM15_CH1,USART2_TX,TIM2_CH3,TSC_G1_IO3,,,,COMP2_OUT,,,,,,,,,ADC1_IN2 +PortA,PA3,TIM15_CH2,USART2_RX,TIM2_CH4,TSC_G1_IO4,,,,,,,,,,,,,ADC1_IN3 +PortA,PA4,SPI1_NSS/I2S1_WS,USART2_CK,,TSC_G2_IO1,TIM14_CH1,USART6_TX,,,,,,,,,,,ADC1_IN4 +PortA,PA5,SPI1_SCK/I2S1_CK,CEC,TIM2_CH1_ETR,TSC_G2_IO2,,USART6_RX,,,,,,,,,,,ADC1_IN5 +PortA,PA6,SPI1_MISO/I2S1_MCK,TIM3_CH1,TIM1_BKIN,TSC_G2_IO3,USART3_CTS,TIM16_CH1,EVENTOUT,COMP1_OUT,,,,,,,,,ADC1_IN6 +PortA,PA7,SPI1_MOSI/I2S1_SD,TIM3_CH2,TIM1_CH1N,TSC_G2_IO4,TIM14_CH1,TIM17_CH1,EVENTOUT,COMP2_OUT,,,,,,,,,ADC1_IN7 +PortA,PA8,MCO,USART1_CK,TIM1_CH1,EVENTOUT,CRS_SYNC,,,,,,,,,,,, +PortA,PA9,TIM15_BKIN,USART1_TX,TIM1_CH2,TSC_G4_IO1,I2C1_SCL,MCO,,,,,,,,,,, +PortA,PA10,TIM17_BKIN,USART1_RX,TIM1_CH3,TSC_G4_IO2,I2C1_SDA,,,,,,,,,,,, +PortA,PA11,EVENTOUT,USART1_CTS,TIM1_CH4,TSC_G4_IO3,CAN1_RX,I2C2_SCL,,COMP1_OUT,,,,,,,,, +PortA,PA12,EVENTOUT,USART1_RTS,TIM1_ETR,TSC_G4_IO4,CAN1_TX,I2C2_SDA,,COMP2_OUT,,,,,,,,, +PortA,PA13,SWDIO,IR_OUT,,,,,,,,,,,,,,, +PortA,PA14,SWCLK,USART2_TX,,,,,,,,,,,,,,, +PortA,PA15,SPI1_NSS/I2S1_WS,USART2_RX,TIM2_CH1_ETR,EVENTOUT,USART4_RTS,,,,,,,,,,,, +PortB,PB0,EVENTOUT,TIM3_CH3,TIM1_CH2N,TSC_G3_IO2,USART3_CK,,,,,,,,,,,,ADC1_IN8 +PortB,PB1,TIM14_CH1,TIM3_CH4,TIM1_CH3N,TSC_G3_IO3,USART3_RTS,,,,,,,,,,,,ADC1_IN9 +PortB,PB2,,,,TSC_G3_IO4,,,,,,,,,,, +PortB,PB3,SPI1_SCK/I2S1_CK,EVENTOUT,TIM2_CH2,TSC_G5_IO1,USART5_TX,,,,,,,,,, +PortB,PB4,SPI1_MISO/I2S1_MCK,TIM3_CH1,EVENTOUT,TSC_G5_IO2,USART5_RX,TIM17_BKIN,,,,,,,,, +PortB,PB5,SPI1_MOSI/I2S1_SD,TIM3_CH2,TIM16_BKIN,I2C1_SMBA,USART5_CK_RTS,,,,,,,,,, +PortB,PB6,USART1_TX,I2C1_SCL,TIM16_CH1N,TSC_G5_IO3,,,,,,,,,,, +PortB,PB7,USART1_RX,I2C1_SDA,TIM17_CH1N,TSC_G5_IO4,USART4_CTS,,,,,,,,,, +PortB,PB8,CEC,I2C1_SCL,TIM16_CH1,TSC_SYNC,CAN1_RX,,,,,,,,,, +PortB,PB9,IR_OUT,I2C1_SDA,TIM17_CH1,EVENTOUT,CAN1_TX,SPI2_NSS/I2S2_WS,,,,,,,,, +PortB,PB10,CEC,I2C2_SCL,TIM2_CH3,TSC_SYNC,USART3_TX,SPI2_SCK/I2S2_CK,,,,,,,,, +PortB,PB11,EVENTOUT,I2C2_SDA,TIM2_CH4,TSC_G6_IO1,USART3_RX,,,,,,,,,, +PortB,PB12,SPI2_NSS/I2S2_WS,EVENTOUT,TIM1_BKIN,TSC_G6_IO2,USART3_CK,TIM15_BKIN,,,,,,,,, +PortB,PB13,SPI2_SCK/I2S2_CK,,TIM1_CH1N,TSC_G6_IO3,USART3_CTS,I2C2_SCL,,,,,,,,, +PortB,PB14,SPI2_MISO/I2S2_MCK,TIM15_CH1,TIM1_CH2N,TSC_G6_IO4,USART3_RTS,I2C2_SDA,,,,,,,,, +PortB,PB15,SPI2_MOSI/I2S2_SD,TIM15_CH2,TIM1_CH3N,TIM15_CH1N,,,,,,,,,,, +PortC,PC0,EVENTOUT,USART7_TX,USART6_TX,,,,,,,,,,,,,,ADC1_IN10 +PortC,PC1,EVENTOUT,USART7_RX,USART6_RX,,,,,,,,,,,,,,ADC1_IN11 +PortC,PC2,EVENTOUT,SPI2_MISO/I2S2_MCK,USART8_TX,,,,,,,,,,,,,,ADC1_IN12 +PortC,PC3,EVENTOUT,SPI2_MOSI/I2S2_SD,USART8_RX,,,,,,,,,,,,,,ADC1_IN13 +PortC,PC4,EVENTOUT,USART3_TX,,,,,,,,,,,,,,,ADC1_IN14 +PortC,PC5,TSC_G3_IO1,USART3_RX,,,,,,,,,,,,,,,ADC1_IN15 +PortC,PC6,TIM3_CH1,USART7_TX,,,,,,,,,,,,,,, +PortC,PC7,TIM3_CH2,USART7_RX,,,,,,,,,,,,,,, +PortC,PC8,TIM3_CH3,USART8_TX,,,,,,,,,,,,,,, +PortC,PC9,TIM3_CH4,USART8_RX,,,,,,,,,,,,,,, +PortC,PC10,USART4_TX,USART3_TX,,,,,,,,,,,,,,, +PortC,PC11,USART4_RX,USART3_RX,,,,,,,,,,,,,,, +PortC,PC12,USART4_CK,USART3_CK,USART5_TX,,,,,,,,,,,,,, +PortC,PC13,,,,,,,,,,,,,,,,, +PortC,PC14,,,,,,,,,,,,,,,,, +PortC,PC15,,,,,,,,,,,,,,,,, +PortD,PD0,CAN1_RX,SPI2_NSS/I2S2_WS,,,,,,,,,,,,,,, +PortD,PD1,CAN1_TX,SPI2_SCK/I2S2_CK,,,,,,,,,,,,,,, +PortD,PD2,TIM3_ETR,USART3_RTS,USART5_RX,,,,,,,,,,,,,, +PortD,PD3,USART2_CTS,SPI2_MISO/I2S2_MCK,,,,,,,,,,,,,,, +PortD,PD4,USART2_RTS,SPI2_MOSI/I2S2_SD,,,,,,,,,,,,,,, +PortD,PD5,USART2_TX,,,,,,,,,,,,,,,, +PortD,PD6,USART2_RX,,,,,,,,,,,,,,,, +PortD,PD7,USART2_CK,,,,,,,,,,,,,,,, +PortD,PD8,USART3_TX,,,,,,,,,,,,,,,, +PortD,PD9,USART3_RX,,,,,,,,,,,,,,,, +PortD,PD10,USART3_CK,,,,,,,,,,,,,,,, +PortD,PD11,USART3_CTS,,,,,,,,,,,,,,,, +PortD,PD12,USART3_RTS,TSC_G8_IO1,USART8_CK_RTS,,,,,,,,,,,,,, +PortD,PD13,USART8_TX,TSC_G8_IO2,,,,,,,,,,,,,,, +PortD,PD14,USART8_RX,TSC_G8_IO3,,,,,,,,,,,,,,, +PortD,PD15,CRS_SYNC,TSC_G8_IO4,USART7_CK_RTS,,,,,,,,,,,,,, +PortE,PE0,TIM16_CH1,EVENTOUT,,,,,,,,,,,,,,, +PortE,PE1,TIM17_CH1,EVENTOUT,,,,,,,,,,,,,,, +PortE,PE2,TIM3_ETR,TSC_G7_IO1,,,,,,,,,,,,,,, +PortE,PE3,TIM3_CH1,TSC_G7_IO2,,,,,,,,,,,,,,, +PortE,PE4,TIM3_CH2,TSC_G7_IO3,,,,,,,,,,,,,,, +PortE,PE5,TIM3_CH3,TSC_G7_IO4,,,,,,,,,,,,,,, +PortE,PE6,TIM3_CH4,,,,,,,,,,,,,,,, +PortE,PE7,TIM1_ETR,USART5_CK_RTS,,,,,,,,,,,,,,, +PortE,PE8,TIM1_CH1N,USART4_TX,,,,,,,,,,,,,,, +PortE,PE9,TIM1_CH1,USART4_RX,,,,,,,,,,,,,,, +PortE,PE10,TIM1_CH2N,USART5_TX,,,,,,,,,,,,,,, +PortE,PE11,TIM1_CH2,USART5_RX,,,,,,,,,,,,,,, +PortE,PE12,TIM1_CH3N,SPI1_NSS/I2S1_WS,,,,,,,,,,,,,,, +PortE,PE13,TIM1_CH3,SPI1_SCK/I2S1_CK,,,,,,,,,,,,,,, +PortE,PE14,TIM1_CH4,SPI1_MISO/I2S1_MCK,,,,,,,,,,,,,,, +PortE,PE15,TIM1_BKIN,SPI1_MOSI/I2S1_SD,,,,,,,,,,,,,,, +PortF,PF0,CRS_SYNC,I2C1_SDA,,,,,,,,,,,,,,, +PortF,PF1,,I2C1_SCL,,,,,,,,,,,,,,, +PortF,PF2,EVENTOUT,USART7_TX,USART7_CK_RTS,,,,,,,,,,,,,, +PortF,PF3,EVENTOUT,USART7_RX,USART6_CK_RTS,,,,,,,,,,,,,, +PortF,PF6,,,,,,,,,,,,,,,,, +PortF,PF9,TIM15_CH1,USART6_TX,,,,,,,,,,,,,,, +PortF,PF10,TIM15_CH2,USART6_RX,,,,,,,,,,,,,,, diff --git a/ports/stm32/boards/stm32f091xc.ld b/ports/stm32/boards/stm32f091xc.ld new file mode 100644 index 0000000000..73b8442957 --- /dev/null +++ b/ports/stm32/boards/stm32f091xc.ld @@ -0,0 +1,26 @@ +/* + GNU linker script for STM32F091xC +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 256K + FLASH_TEXT (rx) : ORIGIN = 0x08000000, LENGTH = 256K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define tho top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x20006800; /* room for a 6k stack */ From e681372017d2af10ab167d2ab8bf4d005dd7cf69 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 28 May 2018 18:12:21 +1000 Subject: [PATCH 730/828] stm32/boards: Add NUCLEO_F091RC board configuration files. --- .../boards/NUCLEO_F091RC/mpconfigboard.h | 59 ++++ .../boards/NUCLEO_F091RC/mpconfigboard.mk | 7 + ports/stm32/boards/NUCLEO_F091RC/pins.csv | 50 +++ .../boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h | 314 ++++++++++++++++++ 4 files changed, 430 insertions(+) create mode 100644 ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h create mode 100644 ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk create mode 100644 ports/stm32/boards/NUCLEO_F091RC/pins.csv create mode 100644 ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h diff --git a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h new file mode 100644 index 0000000000..3546d521bf --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h @@ -0,0 +1,59 @@ +#define MICROPY_HW_BOARD_NAME "NUCLEO-F091RC" +#define MICROPY_HW_MCU_NAME "STM32F091RCT6" + +#define MICROPY_EMIT_THUMB (0) +#define MICROPY_EMIT_INLINE_THUMB (0) +#define MICROPY_PY_USOCKET (0) +#define MICROPY_PY_NETWORK (0) +#define MICROPY_PY_STM (0) +#define MICROPY_PY_PYB_LEGACY (0) +#define MICROPY_VFS_FAT (0) + +#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_ADC (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_TIMER (1) +#define MICROPY_HW_HAS_SWITCH (1) + +// For system clock, board uses internal 48MHz, HSI48 + +// The board has an external 32kHz crystal +#define MICROPY_HW_RTC_USE_LSE (1) + +// UART config +#define MICROPY_HW_UART1_TX (pin_B6) +#define MICROPY_HW_UART1_RX (pin_B7) +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) + +// USART2 is connected to the ST-LINK USB VCP +#define MICROPY_HW_UART_REPL PYB_UART_2 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B8) // Arduino D15, pin 3 on CN10 +#define MICROPY_HW_I2C1_SDA (pin_B9) // Arduino D14, pin 5 on CN10 +#define MICROPY_HW_I2C2_SCL (pin_B10) // Arduino D6, pin 25 on CN10 +#define MICROPY_HW_I2C2_SDA (pin_B11) // pin 18 on CN10 + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A15) // pin 17 on CN7 +#define MICROPY_HW_SPI1_SCK (pin_A5) // Arduino D13, pin 11 on CN10 +#define MICROPY_HW_SPI1_MISO (pin_A6) // Arduino D12, pin 13 on CN10 +#define MICROPY_HW_SPI1_MOSI (pin_A7) // Arduino D11, pin 15 on CN10 +#define MICROPY_HW_SPI2_NSS (pin_B12) // pin 16 on CN10 +#define MICROPY_HW_SPI2_SCK (pin_B13) // pin 30 on CN10 +#define MICROPY_HW_SPI2_MISO (pin_B14) // pin 28 on CN10 +#define MICROPY_HW_SPI2_MOSI (pin_B15) // pin 26 on CN10 + +// USER B1 has a pull-up and is active low +#define MICROPY_HW_USRSW_PIN (pin_C13) +#define MICROPY_HW_USRSW_PULL (0) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) +#define MICROPY_HW_USRSW_PRESSED (0) + +// NUCLEO-64 has one user LED +#define MICROPY_HW_LED1 (pin_A5) // green +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) diff --git a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk new file mode 100644 index 0000000000..1d66f7e6b6 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = f0 +CMSIS_MCU = STM32F091xC +AF_FILE = boards/stm32f091_af.csv +LD_FILES = boards/stm32f091xc.ld boards/common_basic.ld + +# Don't include default frozen modules because MCU is tight on flash space +FROZEN_MPY_DIR ?= diff --git a/ports/stm32/boards/NUCLEO_F091RC/pins.csv b/ports/stm32/boards/NUCLEO_F091RC/pins.csv new file mode 100644 index 0000000000..33f9628bb4 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F091RC/pins.csv @@ -0,0 +1,50 @@ +A0,PA0 +A1,PA1 +A2,PA2 +A3,PA3 +A4,PA4 +A5,PA5 +A6,PA6 +A7,PA7 +A8,PA8 +A9,PA9 +A10,PA10 +A11,PA11 +A12,PA12 +A13,PA13 +A14,PA14 +A15,PA15 +B0,PB0 +B1,PB1 +B2,PB2 +B3,PB3 +B4,PB4 +B5,PB5 +B6,PB6 +B7,PB7 +B8,PB8 +B9,PB9 +B10,PB10 +B11,PB11 +B12,PB12 +B13,PB13 +B14,PB14 +B15,PB15 +C0,PC0 +C1,PC1 +C2,PC2 +C3,PC3 +C4,PC4 +C5,PC5 +C6,PC6 +C7,PC7 +C8,PC8 +C9,PC9 +C10,PC10 +C11,PC11 +C12,PC12 +C13,PC13 +C14,PC14 +C15,PC15 +USER_B1,PC13 +LED_GREEN,PA5 diff --git a/ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h new file mode 100644 index 0000000000..4e4ab9dbfa --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h @@ -0,0 +1,314 @@ +/** + ****************************************************************************** + * @file stm32f0xx_hal_conf_template.h + * @author MCD Application Team + * @brief HAL configuration template file. + * This file should be copied to the application folder and renamed + * to stm32f0xx_hal_conf.h. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F0xx_HAL_CONF_H +#define __STM32F0xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +#define HAL_CEC_MODULE_ENABLED +#define HAL_COMP_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_CRC_MODULE_ENABLED +#define HAL_DAC_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_MODULE_ENABLED +#define HAL_IRDA_MODULE_ENABLED +#define HAL_IWDG_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +#define HAL_SMARTCARD_MODULE_ENABLED +#define HAL_SMBUS_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_TSC_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +#define HAL_USART_MODULE_ENABLED +#define HAL_WWDG_MODULE_ENABLED + +/* ######################### Oscillator Values adaptation ################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +/** + * @brief In the following line adjust the External High Speed oscillator (HSE) Startup + * Timeout value + */ +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT 100U /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE 8000000U /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief In the following line adjust the Internal High Speed oscillator (HSI) Startup + * Timeout value + */ +#if !defined (HSI_STARTUP_TIMEOUT) + #define HSI_STARTUP_TIMEOUT 5000U /*!< Time out for HSI start up */ +#endif /* HSI_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator for ADC (HSI14) value. + */ +#if !defined (HSI14_VALUE) + #define HSI14_VALUE 14000000U /*!< Value of the Internal High Speed oscillator for ADC in Hz. + The real value may vary depending on the variations + in voltage and temperature. */ +#endif /* HSI14_VALUE */ + +/** + * @brief Internal High Speed oscillator for USB (HSI48) value. + */ +#if !defined (HSI48_VALUE) + #define HSI48_VALUE 48000000U /*!< Value of the Internal High Speed oscillator for USB in Hz. + The real value may vary depending on the variations + in voltage and temperature. */ +#endif /* HSI48_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE 40000U +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE 32768U /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +/** + * @brief Time out for LSE start up value in ms. + */ +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT 5000U /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE 3300U /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)(1U<<__NVIC_PRIO_BITS) - 1U) /*!< tick interrupt priority (lowest by default) */ + /* Warning: Must be set to higher priority for HAL_Delay() */ + /* and HAL_GetTick() usage under interrupt context */ +#define USE_RTOS 0U +#define PREFETCH_ENABLE 1U +#define INSTRUCTION_CACHE_ENABLE 0U +#define DATA_CACHE_ENABLE 0U +#define USE_SPI_CRC 1U + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/*#define USE_FULL_ASSERT 1*/ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f0xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f0xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f0xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f0xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f0xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f0xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CEC_MODULE_ENABLED + #include "stm32f0xx_hal_cec.h" +#endif /* HAL_CEC_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED + #include "stm32f0xx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f0xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f0xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f0xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f0xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f0xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f0xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f0xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f0xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f0xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f0xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f0xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED + #include "stm32f0xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f0xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f0xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_TSC_MODULE_ENABLED + #include "stm32f0xx_hal_tsc.h" +#endif /* HAL_TSC_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f0xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f0xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f0xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0U : assert_failed((char *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(char* file, uint32_t line); +#else + #define assert_param(expr) ((void)0U) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F0xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ From 98d1609358bf15ab7c98ba39d40e32002b48dbb3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 28 May 2018 22:04:08 +1000 Subject: [PATCH 731/828] stm32/README: Update to include STM32F0 in list of supported MCUs. --- ports/stm32/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/stm32/README.md b/ports/stm32/README.md index cf539691c8..a0c3b7ff39 100644 --- a/ports/stm32/README.md +++ b/ports/stm32/README.md @@ -2,8 +2,8 @@ MicroPython port to STM32 MCUs ============================== This directory contains the port of MicroPython to ST's line of STM32 -microcontrollers. Supported MCU series are: STM32F4, STM32F7 and STM32L4. -Parts of the code here utilise the STM32Cube HAL library. +microcontrollers. Supported MCU series are: STM32F0, STM32F4, STM32F7 and +STM32L4. Parts of the code here utilise the STM32Cube HAL library. The officially supported boards are the line of pyboards: PYBv1.0 and PYBv1.1 (both with STM32F405), and PYBLITEv1.0 (with STM32F411). See From 50bc34d4a454019fc792b4f5034b75dad5b98168 Mon Sep 17 00:00:00 2001 From: rolandvs Date: Tue, 29 May 2018 11:14:13 +0200 Subject: [PATCH 732/828] stm32/boards: Split combined alt-func labels and fix some other errors. Pins with multiple alt-funcs for the same peripheral (eg USART_CTS_NSS) need to be split into individual alt-funcs for make-pins.py to work correctly. This patch changes the following: - Split `..._CTS_NSS` into `..._CTS/..._NSS` - Split `..._RTS_DE` into `..._RTS/..._DE` - Split `JTDO_SWO` into `JTDO/TRACESWO` for consistency - Fixed `TRACECK` to `TRACECLK` for consistency --- ports/stm32/boards/stm32f401_af.csv | 2 +- ports/stm32/boards/stm32f411_af.csv | 2 +- ports/stm32/boards/stm32h743_af.csv | 14 +++++++------- ports/stm32/boards/stm32l476_af.csv | 26 +++++++++++++------------- ports/stm32/boards/stm32l496_af.csv | 28 ++++++++++++++-------------- 5 files changed, 36 insertions(+), 36 deletions(-) diff --git a/ports/stm32/boards/stm32f401_af.csv b/ports/stm32/boards/stm32f401_af.csv index bdcf9a1fe5..1acb8e4313 100644 --- a/ports/stm32/boards/stm32f401_af.csv +++ b/ports/stm32/boards/stm32f401_af.csv @@ -19,7 +19,7 @@ PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT, PortB,PB0,,TIM1_CH2N,TIM3_CH3,,,,,,,,,,,,,EVENTOUT,ADC1_IN8 PortB,PB1,,TIM1_CH3N,TIM3_CH4,,,,,,,,,,,,,EVENTOUT,ADC1_IN9 PortB,PB2,,,,,,,,,,,,,,,,EVENTOUT, -PortB,PB3,JTDO_SWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK/I2S3_CK,,,I2C2_SDA,,,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK/I2S3_CK,,,I2C2_SDA,,,,,,EVENTOUT, PortB,PB4,JTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,I2S3ext_SD,,I2C3_SDA,,,,,,EVENTOUT, PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI/I2S3_SD,,,,,,,,,EVENTOUT, PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,,,,,,,EVENTOUT, diff --git a/ports/stm32/boards/stm32f411_af.csv b/ports/stm32/boards/stm32f411_af.csv index 4fe794121b..d5b7a61deb 100644 --- a/ports/stm32/boards/stm32f411_af.csv +++ b/ports/stm32/boards/stm32f411_af.csv @@ -19,7 +19,7 @@ PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART1_TX PortB,PB0,,TIM1_CH2N,TIM3_CH3,,,,SPI5_SCK/I2S5_CK,,,,,,,,,EVENTOUT,ADC1_IN8 PortB,PB1,,TIM1_CH3N,TIM3_CH4,,,,SPI5_NSS/I2S5_WS,,,,,,,,,EVENTOUT,ADC1_IN9 PortB,PB2,,,,,,,,,,,,,,,,EVENTOUT, -PortB,PB3,JTDO-SWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,USART1_RX,,I2C2_SDA,,,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,USART1_RX,,I2C2_SDA,,,,,,EVENTOUT, PortB,PB4,JTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,I2S3ext_SD,,I2C3_SDA,,,SDIO_D0,,,EVENTOUT, PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,,,,,SDIO_D3,,,EVENTOUT, PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,,,,,,,EVENTOUT, diff --git a/ports/stm32/boards/stm32h743_af.csv b/ports/stm32/boards/stm32h743_af.csv index 24710d717b..d008ba68b6 100644 --- a/ports/stm32/boards/stm32h743_af.csv +++ b/ports/stm32/boards/stm32h743_af.csv @@ -1,6 +1,6 @@ Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, ,,SYS,TIM1/2/16/17/LPTIM1/HRTIM1,SAI1/TIM3/4/5/12/HRTIM1,LPUART/TIM8/LPTIM2/3/4/5/HRTIM1/DFSDM,I2C1/2/3/4/USART1/TIM15/LPTIM2/DFSDM/CEC,SPI1/2/3/4/5/6/CEC,SPI2/3/SAI1/3/I2C4/UART4/DFSDM,SPI2/3/6/USART1/2/3/6/UART7/SDMMC1,SPI6/SAI2/4/UART4/5/8/LPUART/SDMMC1/SPDIFRX,SAI4/FDCAN1/2/TIM13/14/QUADSPI/FMC/SDMMC2/LCD/SPDIFRX,SAI2/4/TIM8/QUADSPI/SDMMC2/OTG1_HS/OTG2_FS/LCD,I2C4/UART7/SWPMI1/TIM1/8/DFSDM/SDMMC2/MDIOS/ETH,TIM1/8/FMC/SDMMC1/MDIOS/OTG1_FS/LCD,TIM1/DCMI/LCD/COMP,UART5/LCD,SYS,ADC -PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,TIM15_BKIN,,,USART2_CTS_NSS,UART4_TX,SDMMC2_CMD,SAI2_SD_B,ETH_MII_CRS,,,,EVENTOUT, +PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,TIM15_BKIN,,,USART2_CTS/USART2_NSS,UART4_TX,SDMMC2_CMD,SAI2_SD_B,ETH_MII_CRS,,,,EVENTOUT, PortA,PA1,,TIM2_CH2,TIM5_CH2,LPTIM3_OUT,TIM15_CH1N,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,LCD_R2,EVENTOUT, PortA,PA2,,TIM2_CH3,TIM5_CH3,LPTIM4_OUT,TIM15_CH1,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,MDIOS_MDIO,,LCD_R1,EVENTOUT, PortA,PA3,,TIM2_CH4,TIM5_CH4,LPTIM5_OUT,TIM15_CH2,,,USART2_RX,,LCD_B2,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT, @@ -11,7 +11,7 @@ PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SDO,,,SPI6_MOSI,TIM14_CH PortA,PA8,MCO1,TIM1_CH1,HRTIM_CHB2,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,UART7_RX,TIM8_BKIN2_COMP12,LCD_B3,LCD_R6,EVENTOUT, PortA,PA9,,TIM1_CH2,HRTIM_CHC1,LPUART1_TX,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,CAN1_RXFD,,ETH_TX_ER,,DCMI_D0,LCD_R5,EVENTOUT, PortA,PA10,,TIM1_CH3,HRTIM_CHC2,LPUART1_RX,,,,USART1_RX,,CAN1_TXFD,OTG_FS_ID,MDIOS_MDIO,LCD_B4,DCMI_D1,LCD_B1,EVENTOUT, -PortA,PA11,,TIM1_CH4,HRTIM_CHD1,LPUART1_CTS,,SPI2_NSS/I2S2_WS,UART4_RX,USART1_CTS_NSS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT, +PortA,PA11,,TIM1_CH4,HRTIM_CHD1,LPUART1_CTS,,SPI2_NSS/I2S2_WS,UART4_RX,USART1_CTS/USART1_NSS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT, PortA,PA12,,TIM1_ETR,HRTIM_CHD2,LPUART1_RTS,,SPI2_SCK/I2S2_CK,UART4_TX,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT, PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, @@ -29,7 +29,7 @@ PortB,PB9,,TIM17_CH1,TIM4_CH4,DFSDM_DATIN7,I2C1_SDA,SPI2_NSS/I2S2_WS,I2C4_SDA,SD PortB,PB10,,TIM2_CH3,HRTIM_SCOUT,LPTIM2_IN1,I2C2_SCL,SPI2_SCK/I2S2_CK,DFSDM_DATIN7,USART3_TX,,QUADSPI_BK1_NCS,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT, PortB,PB11,,TIM2_CH4,HRTIM_SCIN,LPTIM2_ETR,I2C2_SDA,,DFSDM_CKIN7,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,,LCD_G5,EVENTOUT, PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,DFSDM_DATIN1,USART3_CK,,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,TIM1_BKIN_COMP12,UART5_RX,EVENTOUT, -PortB,PB13,,TIM1_CH1N,,LPTIM2_OUT,,SPI2_SCK/I2S2_CK,DFSDM_CKIN1,USART3_CTS_NSS,,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,UART5_TX,EVENTOUT, +PortB,PB13,,TIM1_CH1N,,LPTIM2_OUT,,SPI2_SCK/I2S2_CK,DFSDM_CKIN1,USART3_CTS/USART3_NSS,,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,UART5_TX,EVENTOUT, PortB,PB14,,TIM1_CH2N,TIM12_CH1,TIM8_CH2N,USART1_TX,SPI2_MISO/I2S2_SDI,DFSDM_DATIN2,USART3_RTS,UART4_RTS,SDMMC2_D0,,,OTG_HS_DM,,,EVENTOUT, PortB,PB15,RTC_REFIN,TIM1_CH3N,TIM12_CH2,TIM8_CH3N,USART1_RX,SPI2_MOSI/I2S2_SDO,DFSDM_CKIN2,,UART4_CTS,SDMMC2_D1,,,OTG_HS_DP,,,EVENTOUT, PortC,PC0,,,,DFSDM_CKIN0,,,DFSDM_DATIN4,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT, @@ -51,7 +51,7 @@ PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT, PortD,PD0,,,,DFSDM_CKIN6,,,SAI3_SCK_A,,UART4_RX,CAN1_RX,,,FMC_D2/FMC_DA2,,,EVENTOUT, PortD,PD1,,,,DFSDM_DATIN6,,,SAI3_SD_A,,UART4_TX,CAN1_TX,,,FMC_D3/FMC_DA3,,,EVENTOUT, PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,DCMI_D11,,EVENTOUT, -PortD,PD3,,,,DFSDM_CKOUT,,SPI2_SCK/I2S2_CK,,USART2_CTS_NSS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT, +PortD,PD3,,,,DFSDM_CKOUT,,SPI2_SCK/I2S2_CK,,USART2_CTS/USART2_NSS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT, PortD,PD4,,,HRTIM_FLT3,,,,SAI3_FS_A,USART2_RTS,,CAN1_RXFD,,,FMC_NOE,,,EVENTOUT, PortD,PD5,,,HRTIM_EEV3,,,,,USART2_TX,,CAN1_TXFD,,,FMC_NWE,,,EVENTOUT, PortD,PD6,,,SAI1_D1,DFSDM_CKIN4,DFSDM_DATIN1,SPI3_MOSI/I2S3_SDO,SAI1_SD_A,USART2_RX,SAI4_SD_A,CAN2_RXFD,SAI4_D1,SDMMC2_CK,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT, @@ -59,7 +59,7 @@ PortD,PD7,,,,DFSDM_DATIN4,,SPI1_MOSI/I2S1_SDO,DFSDM_CKIN1,USART2_CK,,SPDIFRX_IN0 PortD,PD8,,,,DFSDM_CKIN3,,,SAI3_SCK_B,USART3_TX,,SPDIFRX_IN1,,,FMC_D13/FMC_DA13,,,EVENTOUT, PortD,PD9,,,,DFSDM_DATIN3,,,SAI3_SD_B,USART3_RX,,CAN2_RXFD,,,FMC_D14/FMC_DA14,,,EVENTOUT, PortD,PD10,,,,DFSDM_CKOUT,,,SAI3_FS_B,USART3_CK,,CAN2_TXFD,,,FMC_D15/FMC_DA15,,LCD_B3,EVENTOUT, -PortD,PD11,,,,LPTIM2_IN2,I2C4_SMBA,,,USART3_CTS_NSS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16,,,EVENTOUT, +PortD,PD11,,,,LPTIM2_IN2,I2C4_SMBA,,,USART3_CTS/USART3_NSS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16,,,EVENTOUT, PortD,PD12,,LPTIM1_IN1,TIM4_CH1,LPTIM2_IN1,I2C4_SCL,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17,,,EVENTOUT, PortD,PD13,,LPTIM1_OUT,TIM4_CH2,,I2C4_SDA,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT, PortD,PD14,,,TIM4_CH3,,,,SAI3_MCLK_B,,UART8_CTS,,,,FMC_D0/FMC_DA0,,,EVENTOUT, @@ -109,9 +109,9 @@ PortG,PG9,,,,,,SPI1_MISO/I2S1_SDI,,USART6_RX,SPDIFRX_IN3,QUADSPI_BK2_IO2,SAI2_FS PortG,PG10,,,HRTIM_FLT5,,,SPI1_NSS/I2S1_WS,,,,LCD_G3,SAI2_SD_B,,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT, PortG,PG11,,,HRTIM_EEV4,,,SPI1_SCK/I2S1_CK,,,SPDIFRX_IN0,,SDMMC2_D2,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DCMI_D3,LCD_B3,EVENTOUT, PortG,PG12,,LPTIM1_IN1,HRTIM_EEV5,,,SPI6_MISO,,USART6_RTS,SPDIFRX_IN1,LCD_B4,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_NE4,,LCD_B1,EVENTOUT, -PortG,PG13,TRACED0,LPTIM1_OUT,HRTIM_EEV10,,,SPI6_SCK,,USART6_CTS_NSS,,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,LCD_R0,EVENTOUT, +PortG,PG13,TRACED0,LPTIM1_OUT,HRTIM_EEV10,,,SPI6_SCK,,USART6_CTS/USART6_NSS,,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,LCD_R0,EVENTOUT, PortG,PG14,TRACED1,LPTIM1_ETR,,,,SPI6_MOSI,,USART6_TX,,QUADSPI_BK2_IO3,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,LCD_B0,EVENTOUT, -PortG,PG15,,,,,,,,USART6_CTS_NSS,,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT, +PortG,PG15,,,,,,,,USART6_CTS/USART6_NSS,,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT, PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT, PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT, PortH,PH2,,LPTIM1_IN2,,,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT, diff --git a/ports/stm32/boards/stm32l476_af.csv b/ports/stm32/boards/stm32l476_af.csv index a78fc45aba..01db895725 100644 --- a/ports/stm32/boards/stm32l476_af.csv +++ b/ports/stm32/boards/stm32l476_af.csv @@ -1,7 +1,7 @@ Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,, ,,SYS_AF,TIM1/TIM2/TIM5/TIM8/LPTIM1,TIM1/TIM2/TIM3/TIM4/TIM5,TIM8,I2C1/I2C2/I2C3,SPI1/SPI2,SPI3/DFSDM,USART1/USART2/USART3,UART4/UART5/LPUART1,CAN1/TSC,OTG_FS/QUADSPI,LCD,SDMMC1/COMP1/COMP2/FMC/SWPMI1,SAI1/SAI2,TIM2/TIM15/TIM16/TIM17/LPTIM2,EVENTOUT,ADC,COMP PortA,PA0,,TIM2_CH1,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,,,SAI1_EXTCLK,TIM2_ETR,EVENTOUT,ADC12_IN5, -PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS_DE,UART4_RX,,,LCD_SEG0,,,TIM15_CH1N,EVENTOUT,ADC12_IN6, +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS/USART2_DE,UART4_RX,,,LCD_SEG0,,,TIM15_CH1N,EVENTOUT,ADC12_IN6, PortA,PA2,,TIM2_CH3,TIM5_CH3,,,,,USART2_TX,,,,LCD_SEG1,,SAI2_EXTCLK,TIM15_CH1,EVENTOUT,ADC12_IN7, PortA,PA3,,TIM2_CH4,TIM5_CH4,,,,,USART2_RX,,,,LCD_SEG2,,,TIM15_CH2,EVENTOUT,ADC12_IN8, PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS,USART2_CK,,,,,,SAI1_FS_B,LPTIM2_OUT,EVENTOUT,ADC12_IN9, @@ -12,15 +12,15 @@ PortA,PA8,MCO,TIM1_CH1,,,,,,USART1_CK,,,OTG_FS_SOF,LCD_COM0,,,LPTIM2_OUT,EVENTOU PortA,PA9,,TIM1_CH2,,,,,,USART1_TX,,,,LCD_COM1,,,TIM15_BKIN,EVENTOUT,, PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,LCD_COM2,,,TIM17_BKIN,EVENTOUT,, PortA,PA11,,TIM1_CH4,TIM1_BKIN2,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,TIM1_BKIN2_COMP1,,,EVENTOUT,, -PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS_DE,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT,, +PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS/USART1_DE,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT,, PortA,PA13,JTMS/SWDIO,IR_OUT,,,,,,,,,OTG_FS_NOE,,,,,EVENTOUT,, PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT,, -PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,,,SPI1_NSS,SPI3_NSS,,UART4_RTS_DE,TSC_G3_IO1,,LCD_SEG17,,SAI2_FS_B,,EVENTOUT,, +PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,,,SPI1_NSS,SPI3_NSS,,UART4_RTS/UART4_DE,TSC_G3_IO1,,LCD_SEG17,,SAI2_FS_B,,EVENTOUT,, PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,USART3_CK,,,QUADSPI_BK1_IO1,LCD_SEG5,COMP1_OUT,,,EVENTOUT,ADC12_IN15, -PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM_DATIN0,USART3_RTS_DE,,,QUADSPI_BK1_IO0,LCD_SEG6,,,LPTIM2_IN1,EVENTOUT,ADC12_IN16,COMP1_INN +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM_DATIN0,USART3_RTS/USART3_DE,,,QUADSPI_BK1_IO0,LCD_SEG6,,,LPTIM2_IN1,EVENTOUT,ADC12_IN16,COMP1_INN PortB,PB2,RTC_OUT,LPTIM1_OUT,,,I2C3_SMBA,,DFSDM_CKIN0,,,,,,,,,EVENTOUT,,COMP1_INP -PortB,PB3,JTDO-TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK,USART1_RTS_DE,,,,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT,,COMP2_INM -PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,USART1_CTS,UART5_RTS_DE,TSC_G2_IO1,,LCD_SEG8,,SAI1_MCLK_B,TIM17_BKIN,EVENTOUT,,COMP2_INP +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK,USART1_RTS/USART1_DE,,,,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT,,COMP2_INM +PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,USART1_CTS,UART5_RTS/UART5_DE,TSC_G2_IO1,,LCD_SEG8,,SAI1_MCLK_B,TIM17_BKIN,EVENTOUT,,COMP2_INP PortB,PB5,,LPTIM1_IN1,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI,USART1_CK,UART5_CTS,TSC_G2_IO2,,LCD_SEG9,COMP2_OUT,SAI1_SD_B,TIM16_BKIN,EVENTOUT,, PortB,PB6,,LPTIM1_ETR,TIM4_CH1,TIM8_BKIN2,I2C1_SCL,,DFSDM_DATIN5,USART1_TX,,TSC_G2_IO3,,,TIM8_BKIN2_COMP2,SAI1_FS_B,TIM16_CH1N,EVENTOUT,,COMP2_INP PortB,PB7,,LPTIM1_IN2,TIM4_CH2,TIM8_BKIN,I2C1_SDA,,DFSDM_CKIN5,USART1_RX,UART4_CTS,TSC_G2_IO4,,LCD_SEG21,FMC_NL,TIM8_BKIN_COMP1,TIM17_CH1N,EVENTOUT,,COMP2_INM @@ -28,7 +28,7 @@ PortB,PB8,,,TIM4_CH3,,I2C1_SCL,,DFSDM_DATIN6,,,CAN1_RX,,LCD_SEG16,SDMMC1_D4,SAI1 PortB,PB9,,IR_OUT,TIM4_CH4,,I2C1_SDA,SPI2_NSS,DFSDM_CKIN6,,,CAN1_TX,,LCD_COM3,SDMMC1_D5,SAI1_FS_A,TIM17_CH1,EVENTOUT,, PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK,DFSDM_DATIN7,USART3_TX,LPUART1_RX,,QUADSPI_CLK,LCD_SEG10,COMP1_OUT,SAI1_SCK_A,,EVENTOUT,, PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,DFSDM_CKIN7,USART3_RX,LPUART1_TX,,QUADSPI_NCS,LCD_SEG11,COMP2_OUT,,,EVENTOUT,, -PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM_DATIN1,USART3_CK,LPUART1_RTS_DE,TSC_G1_IO1,,LCD_SEG12,SWPMI1_IO,SAI2_FS_A,TIM15_BKIN,EVENTOUT,, +PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM_DATIN1,USART3_CK,LPUART1_RTS/LPUART1_DE,TSC_G1_IO1,,LCD_SEG12,SWPMI1_IO,SAI2_FS_A,TIM15_BKIN,EVENTOUT,, PortB,PB13,,TIM1_CH1N,,,I2C2_SCL,SPI2_SCK,DFSDM_CKIN1,USART3_CTS,LPUART1_CTS,TSC_G1_IO2,,LCD_SEG13,SWPMI1_TX,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,, PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,I2C2_SDA,SPI2_MISO,DFSDM_DATIN2,USART3_RTS_DE,,TSC_G1_IO3,,LCD_SEG14,SWPMI1_RX,SAI2_MCLK_A,TIM15_CH1,EVENTOUT,, PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI,DFSDM_CKIN2,,,TSC_G1_IO4,,LCD_SEG15,SWPMI1_SUSPEND,SAI2_SD_A,TIM15_CH2,EVENTOUT,, @@ -50,9 +50,9 @@ PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,, PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,, PortD,PD0,,,,,,SPI2_NSS,DFSDM_DATIN7,,,CAN1_RX,,,FMC_D2,,,EVENTOUT,, PortD,PD1,,,,,,SPI2_SCK,DFSDM_CKIN7,,,CAN1_TX,,,FMC_D3,,,EVENTOUT,, -PortD,PD2,,,TIM3_ETR,,,,,USART3_RTS_DE,UART5_RX,TSC_SYNC,,LCD_COM7/LCD_SEG31/LCD_SEG43,SDMMC1_CMD,,,EVENTOUT,, +PortD,PD2,,,TIM3_ETR,,,,,USART3_RTS/USART3_DE,UART5_RX,TSC_SYNC,,LCD_COM7/LCD_SEG31/LCD_SEG43,SDMMC1_CMD,,,EVENTOUT,, PortD,PD3,,,,,,SPI2_MISO,DFSDM_DATIN0,USART2_CTS,,,,,FMC_CLK,,,EVENTOUT,, -PortD,PD4,,,,,,SPI2_MOSI,DFSDM_CKIN0,USART2_RTS_DE,,,,,FMC_NOE,,,EVENTOUT,, +PortD,PD4,,,,,,SPI2_MOSI,DFSDM_CKIN0,USART2_RTS/USART2_DE,,,,,FMC_NOE,,,EVENTOUT,, PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT,, PortD,PD6,,,,,,,DFSDM_DATIN1,USART2_RX,,,,,FMC_NWAIT,SAI1_SD_A,,EVENTOUT,, PortD,PD7,,,,,,,DFSDM_CKIN1,USART2_CK,,,,,FMC_NE1,,,EVENTOUT,, @@ -60,13 +60,13 @@ PortD,PD8,,,,,,,,USART3_TX,,,,LCD_SEG28,FMC_D13,,,EVENTOUT,, PortD,PD9,,,,,,,,USART3_RX,,,,LCD_SEG29,FMC_D14,SAI2_MCLK_A,,EVENTOUT,, PortD,PD10,,,,,,,,USART3_CK,,TSC_G6_IO1,,LCD_SEG30,FMC_D15,SAI2_SCK_A,,EVENTOUT,, PortD,PD11,,,,,,,,USART3_CTS,,TSC_G6_IO2,,LCD_SEG31,FMC_A16,SAI2_SD_A,LPTIM2_ETR,EVENTOUT,, -PortD,PD12,,,TIM4_CH1,,,,,USART3_RTS_DE,,TSC_G6_IO3,,LCD_SEG32,FMC_A17,SAI2_FS_A,LPTIM2_IN1,EVENTOUT,, +PortD,PD12,,,TIM4_CH1,,,,,USART3_RTS/USART3_DE,,TSC_G6_IO3,,LCD_SEG32,FMC_A17,SAI2_FS_A,LPTIM2_IN1,EVENTOUT,, PortD,PD13,,,TIM4_CH2,,,,,,,TSC_G6_IO4,,LCD_SEG33,FMC_A18,,LPTIM2_OUT,EVENTOUT,, PortD,PD14,,,TIM4_CH3,,,,,,,,,LCD_SEG34,FMC_D0,,,EVENTOUT,, PortD,PD15,,,TIM4_CH4,,,,,,,,,LCD_SEG35,FMC_D1,,,EVENTOUT,, PortE,PE0,,,TIM4_ETR,,,,,,,,,LCD_SEG36,FMC_NBL0,,TIM16_CH1,EVENTOUT,, PortE,PE1,,,,,,,,,,,,LCD_SEG37,FMC_NBL1,,TIM17_CH1,EVENTOUT,, -PortE,PE2,TRACECK,,TIM3_ETR,,,,,,,TSC_G7_IO1,,LCD_SEG38,FMC_A23,SAI1_MCLK_A,,EVENTOUT,, +PortE,PE2,TRACECLK,,TIM3_ETR,,,,,,,TSC_G7_IO1,,LCD_SEG38,FMC_A23,SAI1_MCLK_A,,EVENTOUT,, PortE,PE3,TRACED0,,TIM3_CH1,,,,,,,TSC_G7_IO2,,LCD_SEG39,FMC_A19,SAI1_SD_B,,EVENTOUT,, PortE,PE4,TRACED1,,TIM3_CH2,,,,DFSDM_DATIN3,,,TSC_G7_IO3,,,FMC_A20,SAI1_FS_A,,EVENTOUT,, PortE,PE5,TRACED2,,TIM3_CH3,,,,DFSDM_CKIN3,,,TSC_G7_IO4,,,FMC_A21,SAI1_SCK_A,,EVENTOUT,, @@ -102,13 +102,13 @@ PortG,PG2,,,,,,SPI1_SCK,,,,,,,FMC_A12,SAI2_SCK_B,,EVENTOUT,, PortG,PG3,,,,,,SPI1_MISO,,,,,,,FMC_A13,SAI2_FS_B,,EVENTOUT,, PortG,PG4,,,,,,SPI1_MOSI,,,,,,,FMC_A14,SAI2_MCLK_B,,EVENTOUT,, PortG,PG5,,,,,,SPI1_NSS,,,LPUART1_CTS,,,,FMC_A15,SAI2_SD_B,,EVENTOUT,, -PortG,PG6,,,,,I2C3_SMBA,,,,LPUART1_RTS_DE,,,,,,,EVENTOUT,, +PortG,PG6,,,,,I2C3_SMBA,,,,LPUART1_RTS/LPUART1_DE,,,,,,,EVENTOUT,, PortG,PG7,,,,,I2C3_SCL,,,,LPUART1_TX,,,,FMC_INT3,,,EVENTOUT,, PortG,PG8,,,,,I2C3_SDA,,,,LPUART1_RX,,,,,,,EVENTOUT,, PortG,PG9,,,,,,,SPI3_SCK,USART1_TX,,,,,FMC_NCE3/FMC_NE2,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,, PortG,PG10,,LPTIM1_IN1,,,,,SPI3_MISO,USART1_RX,,,,,FMC_NE3,SAI2_FS_A,TIM15_CH1,EVENTOUT,, PortG,PG11,,LPTIM1_IN2,,,,,SPI3_MOSI,USART1_CTS,,,,,,SAI2_MCLK_A,TIM15_CH2,EVENTOUT,, -PortG,PG12,,LPTIM1_ETR,,,,,SPI3_NSS,USART1_RTS_DE,,,,,FMC_NE4,SAI2_SD_A,,EVENTOUT,, +PortG,PG12,,LPTIM1_ETR,,,,,SPI3_NSS,USART1_RTS/USART1_DE,,,,,FMC_NE4,SAI2_SD_A,,EVENTOUT,, PortG,PG13,,,,,I2C1_SDA,,,USART1_CK,,,,,FMC_A24,,,EVENTOUT,, PortG,PG14,,,,,I2C1_SCL,,,,,,,,FMC_A25,,,EVENTOUT,, PortG,PG15,,LPTIM1_OUT,,,I2C1_SMBA,,,,,,,,,,,EVENTOUT,, diff --git a/ports/stm32/boards/stm32l496_af.csv b/ports/stm32/boards/stm32l496_af.csv index 874cf0de0a..311770a055 100644 --- a/ports/stm32/boards/stm32l496_af.csv +++ b/ports/stm32/boards/stm32l496_af.csv @@ -1,7 +1,7 @@ Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,,, ,,SYS_AF,TIM1/TIM2/TIM5/TIM8/LPTIM1,TIM1/TIM2/TIM3/TIM4/TIM5,TIM8,I2C1/I2C2/I2C3,SPI1/SPI2,SPI3/DFSDM,USART1/USART2/USART3,UART4/UART5/LPUART1,CAN1/TSC,OTG_FS/QUADSPI,LCD,SDMMC1/COMP1/COMP2/FMC/SWPMI1,SAI1/SAI2,TIM2/TIM15/TIM16/TIM17/LPTIM2,EVENTOUT,ADC,COMP,DAC PortA,PA0,,TIM2_CH1,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,,,SAI1_EXTCLK,TIM2_ETR,EVENTOUT,ADC12_IN5,, -PortA,PA1,,TIM2_CH2,TIM5_CH2,,I2C1_SMBA,SPI1_SCK,,USART2_RTS_DE,UART4_RX,,,LCD_SEG0,,,TIM15_CH1N,EVENTOUT,ADC12_IN6,, +PortA,PA1,,TIM2_CH2,TIM5_CH2,,I2C1_SMBA,SPI1_SCK,,USART2_RTS/USART2_DE,UART4_RX,,,LCD_SEG0,,,TIM15_CH1N,EVENTOUT,ADC12_IN6,, PortA,PA2,,TIM2_CH3,TIM5_CH3,,,,,USART2_TX,LPUART1_TX,,QUADSPI_BK1_NCS,LCD_SEG1,,SAI2_EXTCLK,TIM15_CH1,EVENTOUT,ADC12_IN7,, PortA,PA3,,TIM2_CH4,TIM5_CH4,,,,,USART2_RX,LPUART1_RX,,QUADSPI_CLK,LCD_SEG2,,SAI1_MCLK_A,TIM15_CH2,EVENTOUT,ADC12_IN8,, PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS,USART2_CK,,,DCMI_HSYNC,,,SAI1_FS_B,LPTIM2_OUT,EVENTOUT,ADC12_IN9,,DAC1_OUT1 @@ -12,15 +12,15 @@ PortA,PA8,MCO,TIM1_CH1,,,,,,USART1_CK,,,OTG_FS_SOF,LCD_COM0,SWPMI1_IO,SAI1_SCK_A PortA,PA9,,TIM1_CH2,,SPI2_SCK,I2C1_SCL,DCMI_D0,,USART1_TX,,,,LCD_COM1,,SAI1_FS_A,TIM15_BKIN,EVENTOUT,,, PortA,PA10,,TIM1_CH3,,,I2C1_SDA,DCMI_D1,,USART1_RX,,,OTG_FS_ID,LCD_COM2,,SAI1_SD_A,TIM17_BKIN,EVENTOUT,,, PortA,PA11,,TIM1_CH4,TIM1_BKIN2,,,SPI1_MISO,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,TIM1_BKIN2_COMP1,,,EVENTOUT,,, -PortA,PA12,,TIM1_ETR,,,,SPI1_MOSI,,USART1_RTS_DE,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT,,, +PortA,PA12,,TIM1_ETR,,,,SPI1_MOSI,,USART1_RTS/USART1_DE,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT,,, PortA,PA13,JTMS/SWDIO,IR_OUT,,,,,,,,,OTG_FS_NOE,,SWPMI1_TX,SAI1_SD_B,,EVENTOUT,,, PortA,PA14,JTCK/SWCLK,LPTIM1_OUT,,,I2C1_SMBA,I2C4_SMBA,,,,,OTG_FS_SOF,,SWPMI1_RX,SAI1_FS_B,,EVENTOUT,,, -PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,USART2_RX,,SPI1_NSS,SPI3_NSS,USART3_RTS_DE,UART4_RTS_DE,TSC_G3_IO1,,LCD_SEG17,SWPMI1_SUSPEND,SAI2_FS_B,,EVENTOUT,,, +PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,USART2_RX,,SPI1_NSS,SPI3_NSS,USART3_RTS/USART3_DE,UART4_RTS/UART4_DE,TSC_G3_IO1,,LCD_SEG17,SWPMI1_SUSPEND,SAI2_FS_B,,EVENTOUT,,, PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,SPI1_NSS,,USART3_CK,,,QUADSPI_BK1_IO1,LCD_SEG5,COMP1_OUT,SAI1_EXTCLK,,EVENTOUT,ADC12_IN15,, -PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM1_DATIN0,USART3_RTS_DE,LPUART1_RTS_DE,,QUADSPI_BK1_IO0,LCD_SEG6,,,LPTIM2_IN1,EVENTOUT,ADC12_IN16,COMP1_INM, +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM1_DATIN0,USART3_RTS/USART3_DE,LPUART1_RTS/LPUART1_DE,,QUADSPI_BK1_IO0,LCD_SEG6,,,LPTIM2_IN1,EVENTOUT,ADC12_IN16,COMP1_INM, PortB,PB2,RTC_OUT,LPTIM1_OUT,,,I2C3_SMBA,,DFSDM1_CKIN0,,,,,LCD_VLCD,,,,EVENTOUT,,COMP1_INP, -PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK,USART1_RTS_DE,,,OTG_FS_CRS_SYNC,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT,,COMP2_INM, -PortB,PB4,NJTRST,,TIM3_CH1,,I2C3_SDA,SPI1_MISO,SPI3_MISO,USART1_CTS,UART5_RTS_DE,TSC_G2_IO1,DCMI_D12,LCD_SEG8,,SAI1_MCLK_B,TIM17_BKIN,EVENTOUT,,COMP2_INP, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK,USART1_RTS/USART1_DE,,,OTG_FS_CRS_SYNC,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT,,COMP2_INM, +PortB,PB4,NJTRST,,TIM3_CH1,,I2C3_SDA,SPI1_MISO,SPI3_MISO,USART1_CTS,UART5_RTS/UART5_DE,TSC_G2_IO1,DCMI_D12,LCD_SEG8,,SAI1_MCLK_B,TIM17_BKIN,EVENTOUT,,COMP2_INP, PortB,PB5,,LPTIM1_IN1,TIM3_CH2,CAN2_RX,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI,USART1_CK,UART5_CTS,TSC_G2_IO2,DCMI_D10,LCD_SEG9,COMP2_OUT,SAI1_SD_B,TIM16_BKIN,EVENTOUT,,, PortB,PB6,,LPTIM1_ETR,TIM4_CH1,TIM8_BKIN2,I2C1_SCL,I2C4_SCL,DFSDM1_DATIN5,USART1_TX,CAN2_TX,TSC_G2_IO3,DCMI_D5,,TIM8_BKIN2_COMP2,SAI1_FS_B,TIM16_CH1N,EVENTOUT,,COMP2_INP, PortB,PB7,,LPTIM1_IN2,TIM4_CH2,TIM8_BKIN,I2C1_SDA,I2C4_SDA,DFSDM1_CKIN5,USART1_RX,UART4_CTS,TSC_G2_IO4,DCMI_VSYNC,LCD_SEG21,FMC_NL,TIM8_BKIN_COMP1,TIM17_CH1N,EVENTOUT,,COMP2_INM, @@ -28,9 +28,9 @@ PortB,PB8,,,TIM4_CH3,,I2C1_SCL,,DFSDM1_DATIN6,,,CAN1_RX,DCMI_D6,LCD_SEG16,SDMMC1 PortB,PB9,,IR_OUT,TIM4_CH4,,I2C1_SDA,SPI2_NSS,DFSDM1_CKIN6,,,CAN1_TX,DCMI_D7,LCD_COM3,SDMMC1_D5,SAI1_FS_A,TIM17_CH1,EVENTOUT,,, PortB,PB10,,TIM2_CH3,,I2C4_SCL,I2C2_SCL,SPI2_SCK,DFSDM1_DATIN7,USART3_TX,LPUART1_RX,TSC_SYNC,QUADSPI_CLK,LCD_SEG10,COMP1_OUT,SAI1_SCK_A,,EVENTOUT,,, PortB,PB11,,TIM2_CH4,,I2C4_SDA,I2C2_SDA,,DFSDM1_CKIN7,USART3_RX,LPUART1_TX,,QUADSPI_BK1_NCS,LCD_SEG11,COMP2_OUT,,,EVENTOUT,,, -PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM1_DATIN1,USART3_CK,LPUART1_RTS_DE,TSC_G1_IO1,CAN2_RX,LCD_SEG12,SWPMI1_IO,SAI2_FS_A,TIM15_BKIN,EVENTOUT,,, +PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM1_DATIN1,USART3_CK,LPUART1_RTS/LPUART1_DE,TSC_G1_IO1,CAN2_RX,LCD_SEG12,SWPMI1_IO,SAI2_FS_A,TIM15_BKIN,EVENTOUT,,, PortB,PB13,,TIM1_CH1N,,,I2C2_SCL,SPI2_SCK,DFSDM1_CKIN1,USART3_CTS,LPUART1_CTS,TSC_G1_IO2,CAN2_TX,LCD_SEG13,SWPMI1_TX,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,,, -PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,I2C2_SDA,SPI2_MISO,DFSDM1_DATIN2,USART3_RTS_DE,,TSC_G1_IO3,,LCD_SEG14,SWPMI1_RX,SAI2_MCLK_A,TIM15_CH1,EVENTOUT,,, +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,I2C2_SDA,SPI2_MISO,DFSDM1_DATIN2,USART3_RTS/USART3_DE,,TSC_G1_IO3,,LCD_SEG14,SWPMI1_RX,SAI2_MCLK_A,TIM15_CH1,EVENTOUT,,, PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI,DFSDM1_CKIN2,,,TSC_G1_IO4,,LCD_SEG15,SWPMI1_SUSPEND,SAI2_SD_A,TIM15_CH2,EVENTOUT,,, PortC,PC0,,LPTIM1_IN1,I2C4_SCL,,I2C3_SCL,,DFSDM1_DATIN4,,LPUART1_RX,,,LCD_SEG18,,,LPTIM2_IN1,EVENTOUT,ADC123_IN1,, PortC,PC1,TRACED0,LPTIM1_OUT,I2C4_SDA,SPI2_MOSI,I2C3_SDA,,DFSDM1_CKIN4,,LPUART1_TX,,QUADSPI_BK2_IO0,LCD_SEG19,,SAI1_SD_A,,EVENTOUT,ADC123_IN2,, @@ -50,9 +50,9 @@ PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,,, PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,,, PortD,PD0,,,,,,SPI2_NSS,DFSDM1_DATIN7,,,CAN1_RX,,,FMC_D2,,,EVENTOUT,,, PortD,PD1,,,,,,SPI2_SCK,DFSDM1_CKIN7,,,CAN1_TX,,,FMC_D3,,,EVENTOUT,,, -PortD,PD2,TRACED2,,TIM3_ETR,,,,,USART3_RTS_DE,UART5_RX,TSC_SYNC,DCMI_D11,LCD_COM7/LCD_SEG31/LCD_SEG43,SDMMC1_CMD,,,EVENTOUT,,, +PortD,PD2,TRACED2,,TIM3_ETR,,,,,USART3_RTS/USART3_DE,UART5_RX,TSC_SYNC,DCMI_D11,LCD_COM7/LCD_SEG31/LCD_SEG43,SDMMC1_CMD,,,EVENTOUT,,, PortD,PD3,,,,SPI2_SCK,DCMI_D5,SPI2_MISO,DFSDM1_DATIN0,USART2_CTS,,,QUADSPI_BK2_NCS,,FMC_CLK,,,EVENTOUT,,, -PortD,PD4,,,,,,SPI2_MOSI,DFSDM1_CKIN0,USART2_RTS_DE,,,QUADSPI_BK2_IO0,,FMC_NOE,,,EVENTOUT,,, +PortD,PD4,,,,,,SPI2_MOSI,DFSDM1_CKIN0,USART2_RTS/USART2_DE,,,QUADSPI_BK2_IO0,,FMC_NOE,,,EVENTOUT,,, PortD,PD5,,,,,,,,USART2_TX,,,QUADSPI_BK2_IO1,,FMC_NWE,,,EVENTOUT,,, PortD,PD6,,,,,DCMI_D10,QUADSPI_BK2_IO1,DFSDM1_DATIN1,USART2_RX,,,QUADSPI_BK2_IO2,,FMC_NWAIT,SAI1_SD_A,,EVENTOUT,,, PortD,PD7,,,,,,,DFSDM1_CKIN1,USART2_CK,,,QUADSPI_BK2_IO3,,FMC_NE1,,,EVENTOUT,,, @@ -60,13 +60,13 @@ PortD,PD8,,,,,,,,USART3_TX,,,DCMI_HSYNC,LCD_SEG28,FMC_D13,,,EVENTOUT,,, PortD,PD9,,,,,,,,USART3_RX,,,DCMI_PIXCLK,LCD_SEG29,FMC_D14,SAI2_MCLK_A,,EVENTOUT,,, PortD,PD10,,,,,,,,USART3_CK,,TSC_G6_IO1,,LCD_SEG30,FMC_D15,SAI2_SCK_A,,EVENTOUT,,, PortD,PD11,,,,,I2C4_SMBA,,,USART3_CTS,,TSC_G6_IO2,,LCD_SEG31,FMC_A16,SAI2_SD_A,LPTIM2_ETR,EVENTOUT,,, -PortD,PD12,,,TIM4_CH1,,I2C4_SCL,,,USART3_RTS_DE,,TSC_G6_IO3,,LCD_SEG32,FMC_A17,SAI2_FS_A,LPTIM2_IN1,EVENTOUT,,, +PortD,PD12,,,TIM4_CH1,,I2C4_SCL,,,USART3_RTS/USART3_DE,,TSC_G6_IO3,,LCD_SEG32,FMC_A17,SAI2_FS_A,LPTIM2_IN1,EVENTOUT,,, PortD,PD13,,,TIM4_CH2,,I2C4_SDA,,,,,TSC_G6_IO4,,LCD_SEG33,FMC_A18,,LPTIM2_OUT,EVENTOUT,,, PortD,PD14,,,TIM4_CH3,,,,,,,,,LCD_SEG34,FMC_D0,,,EVENTOUT,,, PortD,PD15,,,TIM4_CH4,,,,,,,,,LCD_SEG35,FMC_D1,,,EVENTOUT,,, PortE,PE0,,,TIM4_ETR,,,,,,,,DCMI_D2,LCD_SEG36,FMC_NBL0,,TIM16_CH1,EVENTOUT,,, PortE,PE1,,,,,,,,,,,DCMI_D3,LCD_SEG37,FMC_NBL1,,TIM17_CH1,EVENTOUT,,, -PortE,PE2,TRACECK,,TIM3_ETR,,,,,,,TSC_G7_IO1,,LCD_SEG38,FMC_A23,SAI1_MCLK_A,,EVENTOUT,,, +PortE,PE2,TRACECLK,,TIM3_ETR,,,,,,,TSC_G7_IO1,,LCD_SEG38,FMC_A23,SAI1_MCLK_A,,EVENTOUT,,, PortE,PE3,TRACED0,,TIM3_CH1,,,,,,,TSC_G7_IO2,,LCD_SEG39,FMC_A19,SAI1_SD_B,,EVENTOUT,,, PortE,PE4,TRACED1,,TIM3_CH2,,,,DFSDM1_DATIN3,,,TSC_G7_IO3,DCMI_D4,,FMC_A20,SAI1_FS_A,,EVENTOUT,,, PortE,PE5,TRACED2,,TIM3_CH3,,,,DFSDM1_CKIN3,,,TSC_G7_IO4,DCMI_D6,,FMC_A21,SAI1_SCK_A,,EVENTOUT,,, @@ -102,13 +102,13 @@ PortG,PG2,,,,,,SPI1_SCK,,,,,,,FMC_A12,SAI2_SCK_B,,EVENTOUT,,, PortG,PG3,,,,,,SPI1_MISO,,,,,,,FMC_A13,SAI2_FS_B,,EVENTOUT,,, PortG,PG4,,,,,,SPI1_MOSI,,,,,,,FMC_A14,SAI2_MCLK_B,,EVENTOUT,,, PortG,PG5,,,,,,SPI1_NSS,,,LPUART1_CTS,,,,FMC_A15,SAI2_SD_B,,EVENTOUT,,, -PortG,PG6,,,,,I2C3_SMBA,,,,LPUART1_RTS_DE,,,,,,,EVENTOUT,,, +PortG,PG6,,,,,I2C3_SMBA,,,,LPUART1_RTS/LPUART1_DE,,,,,,,EVENTOUT,,, PortG,PG7,,,,,I2C3_SCL,,,,LPUART1_TX,,,,FMC_INT,SAI1_MCLK_A,,EVENTOUT,,, PortG,PG8,,,,,I2C3_SDA,,,,LPUART1_RX,,,,,,,EVENTOUT,,, PortG,PG9,,,,,,,SPI3_SCK,USART1_TX,,,,,FMC_NCE/FMC_NE2,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,,, PortG,PG10,,LPTIM1_IN1,,,,,SPI3_MISO,USART1_RX,,,,,FMC_NE3,SAI2_FS_A,TIM15_CH1,EVENTOUT,,, PortG,PG11,,LPTIM1_IN2,,,,,SPI3_MOSI,USART1_CTS,,,,,,SAI2_MCLK_A,TIM15_CH2,EVENTOUT,,, -PortG,PG12,,LPTIM1_ETR,,,,,SPI3_NSS,USART1_RTS_DE,,,,,FMC_NE4,SAI2_SD_A,,EVENTOUT,,, +PortG,PG12,,LPTIM1_ETR,,,,,SPI3_NSS,USART1_RTS/USART1_DE,,,,,FMC_NE4,SAI2_SD_A,,EVENTOUT,,, PortG,PG13,,,,,I2C1_SDA,,,USART1_CK,,,,,FMC_A24,,,EVENTOUT,,, PortG,PG14,,,,,I2C1_SCL,,,,,,,,FMC_A25,,,EVENTOUT,,, PortG,PG15,,LPTIM1_OUT,,,I2C1_SMBA,,,,,,DCMI_D13,,,,,EVENTOUT,,, From 958fa745213d3bef8a70f8993363098f07fc21fe Mon Sep 17 00:00:00 2001 From: rolandvs Date: Tue, 29 May 2018 14:28:09 +0200 Subject: [PATCH 733/828] stm32/boards: Ensure USB OTG power is off for NUCLEO_F767ZI. And update the GPIO init for NUCLEO_H743ZI to consistently use the mphal functions. --- ports/stm32/boards/NUCLEO_F767ZI/board_init.c | 8 ++++++++ ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h | 3 +++ ports/stm32/boards/NUCLEO_F767ZI/pins.csv | 1 + ports/stm32/boards/NUCLEO_H743ZI/board_init.c | 15 ++++----------- 4 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 ports/stm32/boards/NUCLEO_F767ZI/board_init.c diff --git a/ports/stm32/boards/NUCLEO_F767ZI/board_init.c b/ports/stm32/boards/NUCLEO_F767ZI/board_init.c new file mode 100644 index 0000000000..7d25a445d7 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F767ZI/board_init.c @@ -0,0 +1,8 @@ +#include "py/mphal.h" + +void NUCLEO_F767ZI_board_early_init(void) { + // Turn off the USB switch + #define USB_PowerSwitchOn pin_G6 + mp_hal_pin_output(USB_PowerSwitchOn); + mp_hal_pin_low(USB_PowerSwitchOn); +} diff --git a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h index 7de4c33639..3f23d77d48 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h @@ -13,6 +13,9 @@ #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_BOARD_EARLY_INIT NUCLEO_F767ZI_board_early_init +void NUCLEO_F767ZI_board_early_init(void); + // HSE is 25MHz // VCOClock = HSE * PLLN / PLLM = 25 MHz * 432 / 25 = 432 MHz // SYSCLK = VCOClock / PLLP = 432 MHz / 2 = 216 MHz diff --git a/ports/stm32/boards/NUCLEO_F767ZI/pins.csv b/ports/stm32/boards/NUCLEO_F767ZI/pins.csv index 9df4fc7ef7..3cae615dab 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/pins.csv +++ b/ports/stm32/boards/NUCLEO_F767ZI/pins.csv @@ -58,6 +58,7 @@ USB_VBUS,PA9 USB_ID,PA10 USB_DM,PA11 USB_DP,PA12 +USB_POWER,PG6 VCP_TX,PD8 VCP_RX,PD9 UART2_TX,PD5 diff --git a/ports/stm32/boards/NUCLEO_H743ZI/board_init.c b/ports/stm32/boards/NUCLEO_H743ZI/board_init.c index 1a6006c280..04149c37b8 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/board_init.c +++ b/ports/stm32/boards/NUCLEO_H743ZI/board_init.c @@ -1,15 +1,8 @@ -#include STM32_HAL_H +#include "py/mphal.h" void NUCLEO_H743ZI_board_early_init(void) { - GPIO_InitTypeDef GPIO_InitStructure; - - __HAL_RCC_GPIOG_CLK_ENABLE(); - // Turn off the USB switch - GPIO_InitStructure.Pin = GPIO_PIN_6; - GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStructure.Pull = GPIO_PULLDOWN; - GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; - HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); - HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_RESET); + #define USB_PowerSwitchOn pin_G6 + mp_hal_pin_output(USB_PowerSwitchOn); + mp_hal_pin_low(USB_PowerSwitchOn); } From a1acbad27a1e996c8f95b3d1c801aa2e31df9c99 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 30 May 2018 09:54:51 +1000 Subject: [PATCH 734/828] stm32/flash: Increase H7 flash size to full 2MiB. --- ports/stm32/flash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/flash.c b/ports/stm32/flash.c index d3a568858c..26f76a1747 100644 --- a/ports/stm32/flash.c +++ b/ports/stm32/flash.c @@ -77,7 +77,7 @@ static const flash_layout_t flash_layout[] = { #elif defined(STM32H7) static const flash_layout_t flash_layout[] = { - { 0x08000000, 0x20000, 8 }, + { 0x08000000, 0x20000, 16 }, }; #else From 05b13fd292b42f20affc7cae218d92447efbf6d6 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 25 Mar 2018 16:05:32 -0500 Subject: [PATCH 735/828] py/objtype: Fix assertion failures in mp_obj_new_type by checking types. Fixes assertion failures when the arguments to type() were not of valid types, e.g., when making calls like: type("", (), 3) type("", 3, {}) --- py/objtype.c | 13 ++++++++++--- tests/basics/builtin_type.py | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/py/objtype.c b/py/objtype.c index 2ec27c762c..9b57a50517 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -1005,8 +1005,13 @@ const mp_obj_type_t mp_type_type = { }; mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) { - assert(MP_OBJ_IS_TYPE(bases_tuple, &mp_type_tuple)); // MicroPython restriction, for now - assert(MP_OBJ_IS_TYPE(locals_dict, &mp_type_dict)); // MicroPython restriction, for now + // Verify input objects have expected type + if (!MP_OBJ_IS_TYPE(bases_tuple, &mp_type_tuple)) { + mp_raise_TypeError(NULL); + } + if (!MP_OBJ_IS_TYPE(locals_dict, &mp_type_dict)) { + mp_raise_TypeError(NULL); + } // TODO might need to make a copy of locals_dict; at least that's how CPython does it @@ -1015,7 +1020,9 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) mp_obj_t *bases_items; mp_obj_tuple_get(bases_tuple, &bases_len, &bases_items); for (size_t i = 0; i < bases_len; i++) { - assert(MP_OBJ_IS_TYPE(bases_items[i], &mp_type_type)); + if (!MP_OBJ_IS_TYPE(bases_items[i], &mp_type_type)) { + mp_raise_TypeError(NULL); + } mp_obj_type_t *t = MP_OBJ_TO_PTR(bases_items[i]); // TODO: Verify with CPy, tested on function type if (t->make_new == NULL) { diff --git a/tests/basics/builtin_type.py b/tests/basics/builtin_type.py index 83c45c64b9..c5fb36626c 100644 --- a/tests/basics/builtin_type.py +++ b/tests/basics/builtin_type.py @@ -11,3 +11,21 @@ try: type(1, 2) except TypeError: print('TypeError') + +# second arg should be a tuple +try: + type('abc', None, None) +except TypeError: + print('TypeError') + +# third arg should be a dict +try: + type('abc', (), None) +except TypeError: + print('TypeError') + +# elements of second arg (the bases) should be types +try: + type('abc', (1,), {}) +except TypeError: + print('TypeError') From c60589c02b998794837489a6c6e51c4723af097f Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 25 Mar 2018 16:13:49 -0500 Subject: [PATCH 736/828] py/objtype: Fix assertion failures in super_attr by checking type. Fixes assertion failures and segmentation faults when making calls like: super(1, 1).x --- py/objtype.c | 3 +++ tests/basics/class_super.py | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/py/objtype.c b/py/objtype.c index 9b57a50517..77810ce707 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -1112,6 +1112,9 @@ STATIC mp_obj_t super_make_new(const mp_obj_type_t *type_in, size_t n_args, size // 0 arguments are turned into 2 in the compiler // 1 argument is not yet implemented mp_arg_check_num(n_args, n_kw, 2, 2, false); + if (!MP_OBJ_IS_TYPE(args[0], &mp_type_type)) { + mp_raise_TypeError(NULL); + } mp_obj_super_t *o = m_new_obj(mp_obj_super_t); *o = (mp_obj_super_t){{type_in}, args[0], args[1]}; return MP_OBJ_FROM_PTR(o); diff --git a/tests/basics/class_super.py b/tests/basics/class_super.py index 698fe5dff2..b6ee68308a 100644 --- a/tests/basics/class_super.py +++ b/tests/basics/class_super.py @@ -35,6 +35,12 @@ class B(A): return super().foo().count(2) # calling a subsequent method print(B().foo()) +# first arg to super must be a type +try: + super(1, 1) +except TypeError: + print('TypeError') + # store/delete of super attribute not allowed assert hasattr(super(B, B()), 'foo') try: From 98b9f0fc9d0fe14c5f13faf2e9b902422919594c Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 31 May 2018 21:47:26 +1000 Subject: [PATCH 737/828] extmod/modussl_mbedtls: Populate sock member right away in wrap_socket. Otherwise the "sock" member may have an undefined value if wrap_socket fails with an exception and exits early, and then if the finaliser runs it will try to close an invalid stream object. Fixes issue #3828. --- extmod/modussl_mbedtls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/modussl_mbedtls.c b/extmod/modussl_mbedtls.c index bd4b0c7253..636f45f4e4 100644 --- a/extmod/modussl_mbedtls.c +++ b/extmod/modussl_mbedtls.c @@ -124,6 +124,7 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t); #endif o->base.type = &ussl_socket_type; + o->sock = sock; int ret; mbedtls_ssl_init(&o->ssl); @@ -171,7 +172,6 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { } } - o->sock = sock; mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL); if (args->key.u_obj != MP_OBJ_NULL) { From ea22406f7661edcce88defb9d20517ec967a5a9f Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 31 May 2018 21:52:29 +1000 Subject: [PATCH 738/828] extmod/modussl_mbedtls: Use mbedtls_entropy_func for CTR-DRBG entropy. If mbedtls_ctr_drbg_seed() is available in the mbedtls bulid then so should be mbedtls_entropy_func(). Then it's up to the port to configure a valid entropy source, eg via MBEDTLS_ENTROPY_HARDWARE_ALT. --- extmod/modussl_mbedtls.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/extmod/modussl_mbedtls.c b/extmod/modussl_mbedtls.c index 636f45f4e4..1c9dfd17f9 100644 --- a/extmod/modussl_mbedtls.c +++ b/extmod/modussl_mbedtls.c @@ -73,15 +73,6 @@ STATIC void mbedtls_debug(void *ctx, int level, const char *file, int line, cons } #endif -// TODO: FIXME! -STATIC int null_entropy_func(void *data, unsigned char *output, size_t len) { - (void)data; - (void)output; - (void)len; - // enjoy random bytes - return 0; -} - STATIC int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) { mp_obj_t sock = *(mp_obj_t*)ctx; @@ -140,7 +131,7 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { mbedtls_entropy_init(&o->entropy); const byte seed[] = "upy"; - ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, null_entropy_func/*mbedtls_entropy_func*/, &o->entropy, seed, sizeof(seed)); + ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, mbedtls_entropy_func, &o->entropy, seed, sizeof(seed)); if (ret != 0) { goto cleanup; } From 6d87aa54d6a9d7219b93d7f3141b46afa9c70c48 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Jun 2018 13:27:06 +1000 Subject: [PATCH 739/828] stm32/modnetwork: Don't take netif's down when network is deinited. It should be up to the NIC itself to decide if the network interface is removed upon soft reset. Some NICs can keep the interface up over a soft reset, which improves usability of the network. --- ports/stm32/modnetwork.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ports/stm32/modnetwork.c b/ports/stm32/modnetwork.c index 156c73572e..42052e3c71 100644 --- a/ports/stm32/modnetwork.c +++ b/ports/stm32/modnetwork.c @@ -67,12 +67,6 @@ void mod_network_init(void) { } void mod_network_deinit(void) { - #if MICROPY_PY_LWIP - for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) { - netif_remove(netif); - } - // TODO there may be some timeouts that are still pending... - #endif } void mod_network_register_nic(mp_obj_t nic) { From 7437215ad71dd62897190f20a79344c007b5f875 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Jun 2018 13:31:28 +1000 Subject: [PATCH 740/828] stm32/modnetwork: Change base entry of NIC object from type to base. mod_network_nic_type_t doesn't need to be an actual uPy type, it just needs to be an object. --- ports/stm32/modnetwork.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ports/stm32/modnetwork.h b/ports/stm32/modnetwork.h index af46a54a65..fa706d8697 100644 --- a/ports/stm32/modnetwork.h +++ b/ports/stm32/modnetwork.h @@ -40,7 +40,7 @@ struct netif; typedef struct _mod_network_nic_type_t { - mp_obj_type_t base; + mp_obj_base_t base; void (*poll_callback)(void *data, struct netif *netif); } mod_network_nic_type_t; @@ -84,11 +84,11 @@ typedef struct _mod_network_socket_obj_t { }; } mod_network_socket_obj_t; -#endif - extern const mod_network_nic_type_t mod_network_nic_type_wiznet5k; extern const mod_network_nic_type_t mod_network_nic_type_cc3k; +#endif + void mod_network_init(void); void mod_network_deinit(void); void mod_network_register_nic(mp_obj_t nic); From d9f1ecece2f86d3c007ec51853ec499f1aebb21b Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Jun 2018 13:33:14 +1000 Subject: [PATCH 741/828] stm32/modnetwork: Provide generic implementation of ifconfig method. All it needs is a lwIP netif to function. --- ports/stm32/modnetwork.c | 57 ++++++++++++++++++++++++++++++++++++++++ ports/stm32/modnetwork.h | 2 ++ 2 files changed, 59 insertions(+) diff --git a/ports/stm32/modnetwork.c b/ports/stm32/modnetwork.c index 42052e3c71..416a31f6a9 100644 --- a/ports/stm32/modnetwork.c +++ b/ports/stm32/modnetwork.c @@ -31,6 +31,7 @@ #include "py/objlist.h" #include "py/runtime.h" #include "py/mphal.h" +#include "lib/netutils/netutils.h" #include "modnetwork.h" #if MICROPY_PY_NETWORK @@ -39,6 +40,8 @@ #include "lwip/netif.h" #include "lwip/timeouts.h" +#include "lwip/dns.h" +#include "lwip/dhcp.h" u32_t sys_now(void) { return mp_hal_ticks_ms(); @@ -117,4 +120,58 @@ const mp_obj_module_t mp_module_network = { .globals = (mp_obj_dict_t*)&mp_module_network_globals, }; +/*******************************************************************************/ +// Implementations of network methods that can be used by any interface + +#if MICROPY_PY_LWIP + +mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + // Get IP addresses + const ip_addr_t *dns = dns_getserver(0); + mp_obj_t tuple[4] = { + netutils_format_ipv4_addr((uint8_t*)&netif->ip_addr, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&netif->netmask, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&netif->gw, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&dns, NETUTILS_BIG), + }; + return mp_obj_new_tuple(4, tuple); + } else if (args[1] == MP_OBJ_NEW_QSTR(MP_QSTR_dhcp)) { + // Start the DHCP client + if (dhcp_supplied_address(netif)) { + dhcp_renew(netif); + } else { + dhcp_stop(netif); + dhcp_start(netif); + } + + // Wait for DHCP to get IP address + uint32_t start = mp_hal_ticks_ms(); + while (!dhcp_supplied_address(netif)) { + if (mp_hal_ticks_ms() - start > 10000) { + mp_raise_msg(&mp_type_OSError, "timeout waiting for DHCP to get IP address"); + } + mp_hal_delay_ms(100); + } + + return mp_const_none; + } else { + // Release and stop any existing DHCP + dhcp_release(netif); + dhcp_stop(netif); + // Set static IP addresses + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[1], 4, &items); + netutils_parse_ipv4_addr(items[0], (uint8_t*)&netif->ip_addr, NETUTILS_BIG); + netutils_parse_ipv4_addr(items[1], (uint8_t*)&netif->netmask, NETUTILS_BIG); + netutils_parse_ipv4_addr(items[2], (uint8_t*)&netif->gw, NETUTILS_BIG); + ip_addr_t dns; + netutils_parse_ipv4_addr(items[3], (uint8_t*)&dns, NETUTILS_BIG); + dns_setserver(0, &dns); + return mp_const_none; + } +} + +#endif + #endif // MICROPY_PY_NETWORK diff --git a/ports/stm32/modnetwork.h b/ports/stm32/modnetwork.h index fa706d8697..3224d785e6 100644 --- a/ports/stm32/modnetwork.h +++ b/ports/stm32/modnetwork.h @@ -44,6 +44,8 @@ typedef struct _mod_network_nic_type_t { void (*poll_callback)(void *data, struct netif *netif); } mod_network_nic_type_t; +mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_obj_t *args); + #else struct _mod_network_socket_obj_t; From 5a5bc4a61f660829b8f57c297ff90ec43f86b173 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Jun 2018 13:44:09 +1000 Subject: [PATCH 742/828] drivers/wiznet5k: Fix bug with MACRAW socket calculating packet size. --- drivers/wiznet5k/ethernet/socket.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/wiznet5k/ethernet/socket.c b/drivers/wiznet5k/ethernet/socket.c index ec25fcc793..3ffda3a722 100644 --- a/drivers/wiznet5k/ethernet/socket.c +++ b/drivers/wiznet5k/ethernet/socket.c @@ -525,6 +525,7 @@ int32_t WIZCHIP_EXPORT(recvfrom)(uint8_t sn, uint8_t * buf, uint16_t len, uint8_ // read peer's IP address, port number & packet length sock_remained_size[sn] = head[0]; sock_remained_size[sn] = (sock_remained_size[sn] <<8) + head[1]; + sock_remained_size[sn] -= 2; // len includes 2 len bytes if(sock_remained_size[sn] > 1514) { WIZCHIP_EXPORT(close)(sn); From 7d86ac6c0197abddd4ccff92154af326da083558 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Jun 2018 14:21:38 +1000 Subject: [PATCH 743/828] stm32: Add network driver for Wiznet5k using MACRAW mode and lwIP. The Wiznet5k series of chips support a MACRAW mode which allows the host to send and receive Ethernet frames directly. This can be hooked into the lwIP stack to provide a full "socket" implementation using this Wiznet Ethernet device. This patch adds support for this feature. To enable the feature one must add the following to mpconfigboard.mk, or mpconfigport.mk: MICROPY_PY_WIZNET5K = 5500 and the following to mpconfigboard.h, or mpconfigport.h: #define MICROPY_PY_LWIP (1) After wiring up the module (X5=CS, X4=RST), usage on a pyboard is: import time, network nic = network.WIZNET5K(pyb.SPI(1), pyb.Pin.board.X5, pyb.Pin.board.X4) nic.active(1) while not nic.isconnected(): time.sleep_ms(50) # needed to poll the NIC print(nic.ifconfig()) Then use the socket module as usual. Compared to using the built-in TCP/IP stack on the Wiznet module, some performance is lost in MACRAW mode: with a lot of memory allocated to lwIP buffers, lwIP gives Around 750,000 bytes/sec max TCP download, compared with 1M/sec when using the TCP/IP stack on the Wiznet module. --- ports/stm32/Makefile | 2 +- ports/stm32/modnetwork.h | 2 + ports/stm32/modnwwiznet5k.c | 4 + ports/stm32/network_wiznet5k.c | 417 +++++++++++++++++++++++++++++++++ 4 files changed, 424 insertions(+), 1 deletion(-) create mode 100644 ports/stm32/network_wiznet5k.c diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index afb21b048c..a072e106ba 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -328,7 +328,7 @@ ifneq ($(MICROPY_PY_WIZNET5K),0) WIZNET5K_DIR=drivers/wiznet5k INC += -I$(TOP)/$(WIZNET5K_DIR) CFLAGS_MOD += -DMICROPY_PY_WIZNET5K=$(MICROPY_PY_WIZNET5K) -D_WIZCHIP_=$(MICROPY_PY_WIZNET5K) -SRC_MOD += modnwwiznet5k.c +SRC_MOD += network_wiznet5k.c modnwwiznet5k.c SRC_MOD += $(addprefix $(WIZNET5K_DIR)/,\ ethernet/w$(MICROPY_PY_WIZNET5K)/w$(MICROPY_PY_WIZNET5K).c \ ethernet/wizchip_conf.c \ diff --git a/ports/stm32/modnetwork.h b/ports/stm32/modnetwork.h index 3224d785e6..f45e00fbc2 100644 --- a/ports/stm32/modnetwork.h +++ b/ports/stm32/modnetwork.h @@ -44,6 +44,8 @@ typedef struct _mod_network_nic_type_t { void (*poll_callback)(void *data, struct netif *netif); } mod_network_nic_type_t; +extern const mp_obj_type_t mod_network_nic_type_wiznet5k; + mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_obj_t *args); #else diff --git a/ports/stm32/modnwwiznet5k.c b/ports/stm32/modnwwiznet5k.c index 017bd42f88..bf4b72ff21 100644 --- a/ports/stm32/modnwwiznet5k.c +++ b/ports/stm32/modnwwiznet5k.c @@ -38,6 +38,8 @@ #include "pin.h" #include "spi.h" +#if MICROPY_PY_WIZNET5K && !MICROPY_PY_LWIP + #include "ethernet/wizchip_conf.h" #include "ethernet/socket.h" #include "internet/dns/dns.h" @@ -499,3 +501,5 @@ const mod_network_nic_type_t mod_network_nic_type_wiznet5k = { .settimeout = wiznet5k_socket_settimeout, .ioctl = wiznet5k_socket_ioctl, }; + +#endif // MICROPY_PY_WIZNET5K && !MICROPY_PY_LWIP diff --git a/ports/stm32/network_wiznet5k.c b/ports/stm32/network_wiznet5k.c new file mode 100644 index 0000000000..9db42b7874 --- /dev/null +++ b/ports/stm32/network_wiznet5k.c @@ -0,0 +1,417 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "py/runtime.h" +#include "py/mphal.h" +#include "spi.h" +#include "modnetwork.h" + +#if MICROPY_PY_WIZNET5K && MICROPY_PY_LWIP + +#include "drivers/wiznet5k/ethernet/socket.h" +#include "lwip/err.h" +#include "lwip/dns.h" +#include "lwip/dhcp.h" +#include "netif/etharp.h" + +/*******************************************************************************/ +// Wiznet5k Ethernet driver in MACRAW mode + +typedef struct _wiznet5k_obj_t { + mod_network_nic_type_t base; + mp_uint_t cris_state; + const spi_t *spi; + mp_hal_pin_obj_t cs; + mp_hal_pin_obj_t rst; + uint8_t eth_frame[1514]; + struct netif netif; + struct dhcp dhcp_struct; +} wiznet5k_obj_t; + +// Global object holding the Wiznet5k state +STATIC wiznet5k_obj_t wiznet5k_obj; + +STATIC void wiznet5k_lwip_init(wiznet5k_obj_t *self); +STATIC void wiznet5k_lwip_poll(void *self_in, struct netif *netif); + +STATIC void wiz_cris_enter(void) { + wiznet5k_obj.cris_state = MICROPY_BEGIN_ATOMIC_SECTION(); +} + +STATIC void wiz_cris_exit(void) { + MICROPY_END_ATOMIC_SECTION(wiznet5k_obj.cris_state); +} + +STATIC void wiz_cs_select(void) { + mp_hal_pin_low(wiznet5k_obj.cs); +} + +STATIC void wiz_cs_deselect(void) { + mp_hal_pin_high(wiznet5k_obj.cs); +} + +STATIC void wiz_spi_read(uint8_t *buf, uint32_t len) { + HAL_StatusTypeDef status = HAL_SPI_Receive(wiznet5k_obj.spi->spi, buf, len, 5000); + (void)status; +} + +STATIC void wiz_spi_write(const uint8_t *buf, uint32_t len) { + HAL_StatusTypeDef status = HAL_SPI_Transmit(wiznet5k_obj.spi->spi, (uint8_t*)buf, len, 5000); + (void)status; +} + +STATIC void wiznet5k_init(void) { + // SPI configuration + SPI_InitTypeDef *init = &wiznet5k_obj.spi->spi->Init; + init->Mode = SPI_MODE_MASTER; + init->Direction = SPI_DIRECTION_2LINES; + init->DataSize = SPI_DATASIZE_8BIT; + init->CLKPolarity = SPI_POLARITY_LOW; // clock is low when idle + init->CLKPhase = SPI_PHASE_1EDGE; // data latched on first edge, which is rising edge for low-idle + init->NSS = SPI_NSS_SOFT; + init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; // clock freq = f_PCLK / this_prescale_value; Wiz820i can do up to 80MHz + init->FirstBit = SPI_FIRSTBIT_MSB; + init->TIMode = SPI_TIMODE_DISABLED; + init->CRCCalculation = SPI_CRCCALCULATION_DISABLED; + init->CRCPolynomial = 7; // unused + spi_init(wiznet5k_obj.spi, false); + + mp_hal_pin_output(wiznet5k_obj.cs); + mp_hal_pin_output(wiznet5k_obj.rst); + + // Reset the chip + mp_hal_pin_low(wiznet5k_obj.rst); + mp_hal_delay_ms(1); // datasheet says 2us + mp_hal_pin_high(wiznet5k_obj.rst); + mp_hal_delay_ms(150); // datasheet says 150ms + + // Set physical interface callbacks + reg_wizchip_cris_cbfunc(wiz_cris_enter, wiz_cris_exit); + reg_wizchip_cs_cbfunc(wiz_cs_select, wiz_cs_deselect); + reg_wizchip_spi_cbfunc(wiz_spi_read, wiz_spi_write); + + // Configure 16k buffers for fast MACRAW + uint8_t sn_size[16] = {16, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0}; + ctlwizchip(CW_INIT_WIZCHIP, sn_size); + + // Seems we need a small delay after init + mp_hal_delay_ms(250); + + // Hook the Wiznet into lwIP + wiznet5k_lwip_init(&wiznet5k_obj); +} + +STATIC void wiznet5k_deinit(void) { + for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) { + if (netif == &wiznet5k_obj.netif) { + netif_remove(netif); + netif->flags = 0; + break; + } + } +} + +STATIC void wiznet5k_get_mac_address(wiznet5k_obj_t *self, uint8_t mac[6]) { + (void)self; + getSHAR(mac); +} + +STATIC void wiznet5k_send_ethernet(wiznet5k_obj_t *self, size_t len, const uint8_t *buf) { + uint8_t ip[4] = {1, 1, 1, 1}; // dummy + int ret = WIZCHIP_EXPORT(sendto)(0, (byte*)buf, len, ip, 11); // dummy port + if (ret != len) { + printf("wiznet5k_send_ethernet: fatal error %d\n", ret); + netif_set_link_down(&self->netif); + netif_set_down(&self->netif); + } +} + +// Stores the frame in self->eth_frame and returns number of bytes in the frame, 0 for no frame +STATIC uint16_t wiznet5k_recv_ethernet(wiznet5k_obj_t *self) { + uint16_t len = getSn_RX_RSR(0); + if (len == 0) { + return 0; + } + + byte ip[4]; + uint16_t port; + int ret = WIZCHIP_EXPORT(recvfrom)(0, self->eth_frame, 1514, ip, &port); + if (ret <= 0) { + printf("wiznet5k_lwip_poll: fatal error len=%u ret=%d\n", len, ret); + netif_set_link_down(&self->netif); + netif_set_down(&self->netif); + return 0; + } + + return ret; +} + +/*******************************************************************************/ +// Wiznet5k lwIP interface + +STATIC err_t wiznet5k_netif_output(struct netif *netif, struct pbuf *p) { + wiznet5k_obj_t *self = netif->state; + pbuf_copy_partial(p, self->eth_frame, p->tot_len, 0); + wiznet5k_send_ethernet(self, p->tot_len, self->eth_frame); + return ERR_OK; +} + +STATIC err_t wiznet5k_netif_init(struct netif *netif) { + netif->linkoutput = wiznet5k_netif_output; + netif->output = etharp_output; + netif->mtu = 1500; + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP; + wiznet5k_get_mac_address(netif->state, netif->hwaddr); + netif->hwaddr_len = sizeof(netif->hwaddr); + int ret = WIZCHIP_EXPORT(socket)(0, Sn_MR_MACRAW, 0, 0); + if (ret != 0) { + printf("WIZNET fatal error in netifinit: %d\n", ret); + return ERR_IF; + } + + // Enable MAC filtering so we only get frames destined for us, to reduce load on lwIP + setSn_MR(0, getSn_MR(0) | Sn_MR_MFEN); + + return ERR_OK; +} + +STATIC void wiznet5k_lwip_init(wiznet5k_obj_t *self) { + ip_addr_t ipconfig[4]; + ipconfig[0].addr = 0; + ipconfig[1].addr = 0; + ipconfig[2].addr = 0; + ipconfig[3].addr = 0; + netif_add(&self->netif, &ipconfig[0], &ipconfig[1], &ipconfig[2], self, wiznet5k_netif_init, ethernet_input); + self->netif.name[0] = 'e'; + self->netif.name[1] = '0'; + netif_set_default(&self->netif); + dns_setserver(0, &ipconfig[3]); + dhcp_set_struct(&self->netif, &self->dhcp_struct); + // Setting NETIF_FLAG_UP then clearing it is a workaround for dhcp_start and the + // LWIP_DHCP_CHECK_LINK_UP option, so that the DHCP client schedules itself to + // automatically start when the interface later goes up. + self->netif.flags |= NETIF_FLAG_UP; + dhcp_start(&self->netif); + self->netif.flags &= ~NETIF_FLAG_UP; +} + +STATIC void wiznet5k_lwip_poll(void *self_in, struct netif *netif) { + wiznet5k_obj_t *self = self_in; + uint16_t len; + while ((len = wiznet5k_recv_ethernet(self)) > 0) { + struct pbuf *p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); + if (p != NULL) { + pbuf_take(p, self->eth_frame, len); + if (self->netif.input(p, &self->netif) != ERR_OK) { + pbuf_free(p); + } + } + } +} + +/*******************************************************************************/ +// MicroPython bindings + +// WIZNET5K([spi, pin_cs, pin_rst]) +STATIC mp_obj_t wiznet5k_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 3, 3, false); + + const spi_t *spi = spi_from_mp_obj(args[0]); + mp_hal_pin_obj_t cs = pin_find(args[1]); + mp_hal_pin_obj_t rst = pin_find(args[2]); + + // Access the existing object, if it has been constructed with the same hardware interface + if (wiznet5k_obj.base.base.type == &mod_network_nic_type_wiznet5k) { + if (!(wiznet5k_obj.spi == spi && wiznet5k_obj.cs == cs && wiznet5k_obj.rst == rst + && wiznet5k_obj.netif.flags != 0)) { + wiznet5k_deinit(); + } + } + + // Init the wiznet5k object + wiznet5k_obj.base.base.type = &mod_network_nic_type_wiznet5k; + wiznet5k_obj.base.poll_callback = wiznet5k_lwip_poll; + wiznet5k_obj.cris_state = 0; + wiznet5k_obj.spi = spi; + wiznet5k_obj.cs = cs; + wiznet5k_obj.rst = rst; + + // Return wiznet5k object + return MP_OBJ_FROM_PTR(&wiznet5k_obj); +} + +STATIC mp_obj_t wiznet5k_regs(mp_obj_t self_in) { + (void)self_in; + printf("Wiz CREG:"); + for (int i = 0; i < 0x50; ++i) { + if (i % 16 == 0) { + printf("\n %04x:", i); + } + #if MICROPY_PY_WIZNET5K == 5200 + uint32_t reg = i; + #else + uint32_t reg = _W5500_IO_BASE_ | i << 8; + #endif + printf(" %02x", WIZCHIP_READ(reg)); + } + for (int sn = 0; sn < 4; ++sn) { + printf("\nWiz SREG[%d]:", sn); + for (int i = 0; i < 0x30; ++i) { + if (i % 16 == 0) { + printf("\n %04x:", i); + } + #if MICROPY_PY_WIZNET5K == 5200 + uint32_t reg = WIZCHIP_SREG_ADDR(sn, i); + #else + uint32_t reg = _W5500_IO_BASE_ | i << 8 | WIZCHIP_SREG_BLOCK(sn) << 3; + #endif + printf(" %02x", WIZCHIP_READ(reg)); + } + } + printf("\n"); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(wiznet5k_regs_obj, wiznet5k_regs); + +STATIC mp_obj_t wiznet5k_isconnected(mp_obj_t self_in) { + wiznet5k_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool( + wizphy_getphylink() == PHY_LINK_ON + && (self->netif.flags & NETIF_FLAG_UP) + && self->netif.ip_addr.addr != 0 + ); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(wiznet5k_isconnected_obj, wiznet5k_isconnected); + +STATIC mp_obj_t wiznet5k_active(size_t n_args, const mp_obj_t *args) { + wiznet5k_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + return mp_obj_new_bool(self->netif.flags & NETIF_FLAG_UP); + } else { + if (mp_obj_is_true(args[1])) { + if (!(self->netif.flags & NETIF_FLAG_UP)) { + wiznet5k_init(); + netif_set_link_up(&self->netif); + netif_set_up(&self->netif); + } + } else { + if (self->netif.flags & NETIF_FLAG_UP) { + netif_set_down(&self->netif); + netif_set_link_down(&self->netif); + wiznet5k_deinit(); + } + } + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wiznet5k_active_obj, 1, 2, wiznet5k_active); + +STATIC mp_obj_t wiznet5k_ifconfig(size_t n_args, const mp_obj_t *args) { + wiznet5k_obj_t *self = MP_OBJ_TO_PTR(args[0]); + return mod_network_nic_ifconfig(&self->netif, n_args - 1, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wiznet5k_ifconfig_obj, 1, 2, wiznet5k_ifconfig); + +STATIC mp_obj_t wiznet5k_status(size_t n_args, const mp_obj_t *args) { + wiznet5k_obj_t *self = MP_OBJ_TO_PTR(args[0]); + (void)self; + + if (n_args == 1) { + // No arguments: return link status + if (self->netif.flags && wizphy_getphylink() == PHY_LINK_ON) { + if ((self->netif.flags & NETIF_FLAG_UP) && self->netif.ip_addr.addr != 0) { + return MP_OBJ_NEW_SMALL_INT(2); + } else { + return MP_OBJ_NEW_SMALL_INT(1); + } + } else { + return MP_OBJ_NEW_SMALL_INT(0); + } + } + + mp_raise_ValueError("unknown config param"); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wiznet5k_status_obj, 1, 2, wiznet5k_status); + +STATIC mp_obj_t wiznet5k_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + wiznet5k_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + if (kwargs->used == 0) { + // Get config value + if (n_args != 2) { + mp_raise_TypeError("must query one param"); + } + + switch (mp_obj_str_get_qstr(args[1])) { + case MP_QSTR_mac: { + uint8_t buf[6]; + wiznet5k_get_mac_address(self, buf); + return mp_obj_new_bytes(buf, 6); + } + default: + mp_raise_ValueError("unknown config param"); + } + } else { + // Set config value(s) + if (n_args != 1) { + mp_raise_TypeError("can't specify pos and kw args"); + } + mp_raise_ValueError("unknown config param"); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wiznet5k_config_obj, 1, wiznet5k_config); + +STATIC mp_obj_t send_ethernet_wrapper(mp_obj_t self_in, mp_obj_t buf_in) { + wiznet5k_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t buf; + mp_get_buffer_raise(buf_in, &buf, MP_BUFFER_READ); + wiznet5k_send_ethernet(self, buf.len, buf.buf); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(send_ethernet_obj, send_ethernet_wrapper); + +STATIC const mp_rom_map_elem_t wiznet5k_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_regs), MP_ROM_PTR(&wiznet5k_regs_obj) }, + { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&wiznet5k_isconnected_obj) }, + { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&wiznet5k_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&wiznet5k_ifconfig_obj) }, + { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&wiznet5k_status_obj) }, + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&wiznet5k_config_obj) }, + + { MP_ROM_QSTR(MP_QSTR_send_ethernet), MP_ROM_PTR(&send_ethernet_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(wiznet5k_locals_dict, wiznet5k_locals_dict_table); + +const mp_obj_type_t mod_network_nic_type_wiznet5k = { + { &mp_type_type }, + .name = MP_QSTR_WIZNET5K, + .make_new = wiznet5k_make_new, + .locals_dict = (mp_obj_dict_t*)&wiznet5k_locals_dict, +}; + +#endif // MICROPY_PY_WIZNET5K && MICROPY_PY_LWIP From 309fe39dbb14b1f715ea09c4b9de235a099c01b0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 3 Jun 2018 21:50:49 +1000 Subject: [PATCH 744/828] stm32/modnetwork: Fix arg indexing in generic ifconfig method. --- ports/stm32/modnetwork.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/stm32/modnetwork.c b/ports/stm32/modnetwork.c index 416a31f6a9..cf7ecbf3c0 100644 --- a/ports/stm32/modnetwork.c +++ b/ports/stm32/modnetwork.c @@ -136,7 +136,7 @@ mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_o netutils_format_ipv4_addr((uint8_t*)&dns, NETUTILS_BIG), }; return mp_obj_new_tuple(4, tuple); - } else if (args[1] == MP_OBJ_NEW_QSTR(MP_QSTR_dhcp)) { + } else if (args[0] == MP_OBJ_NEW_QSTR(MP_QSTR_dhcp)) { // Start the DHCP client if (dhcp_supplied_address(netif)) { dhcp_renew(netif); @@ -161,7 +161,7 @@ mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_o dhcp_stop(netif); // Set static IP addresses mp_obj_t *items; - mp_obj_get_array_fixed_n(args[1], 4, &items); + mp_obj_get_array_fixed_n(args[0], 4, &items); netutils_parse_ipv4_addr(items[0], (uint8_t*)&netif->ip_addr, NETUTILS_BIG); netutils_parse_ipv4_addr(items[1], (uint8_t*)&netif->netmask, NETUTILS_BIG); netutils_parse_ipv4_addr(items[2], (uint8_t*)&netif->gw, NETUTILS_BIG); From 1427f8f593062a9f428d40e8d3536c6a97adc479 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 4 Jun 2018 16:53:17 +1000 Subject: [PATCH 745/828] py/stream: Move definition of mp_stream_p_t from obj.h to stream.h. Since a long time now, mp_obj_type_t no longer refers explicitly to mp_stream_p_t but rather to an abstract "const void *protocol". So there's no longer any need to define mp_stream_p_t in obj.h and it can go with all its associated definitions in stream.h. Pretty much all users of this type will already include the stream header. --- py/obj.h | 10 ---------- py/stream.h | 10 ++++++++++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/py/obj.h b/py/obj.h index 95a94836e7..8e4083920a 100644 --- a/py/obj.h +++ b/py/obj.h @@ -451,16 +451,6 @@ typedef struct _mp_buffer_p_t { bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); -// Stream protocol -typedef struct _mp_stream_p_t { - // On error, functions should return MP_STREAM_ERROR and fill in *errcode (values - // are implementation-dependent, but will be exposed to user, e.g. via exception). - mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode); - mp_uint_t (*write)(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode); - mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode); - mp_uint_t is_text : 1; // default is bytes, set this for text stream -} mp_stream_p_t; - struct _mp_obj_type_t { // A type is an object so must start with this entry, which points to mp_type_type. mp_obj_base_t base; diff --git a/py/stream.h b/py/stream.h index a1d1c4f8af..3dec49a2e9 100644 --- a/py/stream.h +++ b/py/stream.h @@ -62,6 +62,16 @@ struct mp_stream_seek_t { #define MP_SEEK_CUR (1) #define MP_SEEK_END (2) +// Stream protocol +typedef struct _mp_stream_p_t { + // On error, functions should return MP_STREAM_ERROR and fill in *errcode (values + // are implementation-dependent, but will be exposed to user, e.g. via exception). + mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode); + mp_uint_t (*write)(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode); + mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode); + mp_uint_t is_text : 1; // default is bytes, set this for text stream +} mp_stream_p_t; + MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read1_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto_obj); From df13ecde06c1d9a4f6c46cedc9d9da179178cd7f Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 4 Jun 2018 16:58:45 +1000 Subject: [PATCH 746/828] cc3200/mods: Include stream.h to get definition of mp_stream_p_t. --- ports/cc3200/mods/modusocket.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/cc3200/mods/modusocket.h b/ports/cc3200/mods/modusocket.h index 6e7758662e..aaee04ce19 100644 --- a/ports/cc3200/mods/modusocket.h +++ b/ports/cc3200/mods/modusocket.h @@ -26,6 +26,8 @@ #ifndef MICROPY_INCLUDED_CC3200_MODS_MODUSOCKET_H #define MICROPY_INCLUDED_CC3200_MODS_MODUSOCKET_H +#include "py/stream.h" + extern const mp_obj_dict_t socket_locals_dict; extern const mp_stream_p_t socket_stream_p; From bc92206f89bfa82b96aaf1f93f41d7a4bc40140c Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 4 Jun 2018 11:24:15 +1000 Subject: [PATCH 747/828] esp32/Makefile: Extract common C & C++ flags for consistent compilation. --- ports/esp32/Makefile | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index c8e2f67d39..d6a748bfda 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -94,13 +94,20 @@ INC_ESPCOMP += -I$(ESPCOMP)/app_trace/include INC_ESPCOMP += -I$(ESPCOMP)/app_update/include INC_ESPCOMP += -I$(ESPCOMP)/pthread/include -CFLAGS_BASE = -std=gnu99 -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -mlongcalls -nostdlib -Wall -Werror -Wno-error=unused-function -Wno-error=unused-but-set-variable -Wno-error=unused-variable -Wno-error=deprecated-declarations -DMBEDTLS_CONFIG_FILE='"mbedtls/esp_config.h"' -DHAVE_CONFIG_H -DESP_PLATFORM +# these flags are common to C and C++ compilation +CFLAGS_COMMON = -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfields \ + -mlongcalls -nostdlib \ + -Wall -Werror -Wno-error=unused-function -Wno-error=unused-but-set-variable \ + -Wno-error=unused-variable -Wno-error=deprecated-declarations \ + -DESP_PLATFORM + +CFLAGS_BASE = -std=gnu99 $(CFLAGS_COMMON) -DMBEDTLS_CONFIG_FILE='"mbedtls/esp_config.h"' -DHAVE_CONFIG_H CFLAGS = $(CFLAGS_BASE) $(INC) $(INC_ESPCOMP) CFLAGS += -DIDF_VER=\"$(IDF_VER)\" CFLAGS += $(CFLAGS_MOD) # this is what ESPIDF uses for c++ compilation -CXXFLAGS = -std=gnu++11 -fno-exceptions -fno-rtti -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -mlongcalls -nostdlib -Wall -Werror -Wno-error=unused-function -Wno-error=unused-but-set-variable -Wno-error=unused-variable -Wno-error=deprecated-declarations -DESP_PLATFORM $(INC) $(INC_ESPCOMP) +CXXFLAGS = -std=gnu++11 $(CFLAGS_COMMON) $(INC) $(INC_ESPCOMP) LDFLAGS = -nostdlib -Map=$(@:.elf=.map) --cref LDFLAGS += --gc-sections -static -EL From a90124a9e20fac828aa6e7702f8196092ee354b0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 5 Jun 2018 13:52:22 +1000 Subject: [PATCH 748/828] esp32: Add support for building with external SPI RAM. This patch adds support for building the firmware with external SPI RAM enabled. It is disabled by default because it adds overhead (due to silicon workarounds) and reduces performance (because it's slower to have bytecode and objects stored in external RAM). To enable it, either use "make CONFIG_SPIRAM_SUPPORT=1", or add this line to you custom makefile/GNUmakefile (before "include Makefile"): CONFIG_SPIRAM_SUPPORT = 1 When this option is enabled the MicroPython heap is automatically allocated in external SPI RAM. Thanks to Angus Gratton for help with the compiler and linker settings. --- ports/esp32/Makefile | 15 ++++++++++++--- ports/esp32/README.md | 1 + ports/esp32/sdkconfig.h | 13 +++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index d6a748bfda..929156f8a3 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -117,7 +117,6 @@ LDFLAGS += -L$(ESPCOMP)/esp32/ld LDFLAGS += -T $(BUILD)/esp32_out.ld LDFLAGS += -T ./esp32.custom_common.ld LDFLAGS += -T esp32.rom.ld -LDFLAGS += -T esp32.rom.spiram_incompatible_fns.ld LDFLAGS += -T esp32.peripherals.ld LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) @@ -133,6 +132,15 @@ COPT += -Os -DNDEBUG #LDFLAGS += --gc-sections endif +# Enable SPIRAM support if CONFIG_SPIRAM_SUPPORT=1 +ifeq ($(CONFIG_SPIRAM_SUPPORT),1) +CFLAGS_COMMON += -mfix-esp32-psram-cache-issue -DCONFIG_SPIRAM_SUPPORT=1 +LIBC_LIBM = $(ESPCOMP)/newlib/lib/libc-psram-workaround.a $(ESPCOMP)/newlib/lib/libm-psram-workaround.a +else +LDFLAGS += -T esp32.rom.spiram_incompatible_fns.ld +LIBC_LIBM = $(ESPCOMP)/newlib/lib/libc.a $(ESPCOMP)/newlib/lib/libm.a +endif + ################################################################################ # List of MicroPython source and object files @@ -266,6 +274,8 @@ ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\ wifi_init.o \ wifi_internal.o \ sleep_modes.o \ + spiram.o \ + spiram_psram.o \ ) ESPIDF_HEAP_O = $(addprefix $(ESPCOMP)/heap/,\ @@ -655,8 +665,7 @@ APP_LD_ARGS += $(LDFLAGS_MOD) APP_LD_ARGS += --start-group APP_LD_ARGS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc APP_LD_ARGS += -L$(dir $(LIBSTDCXX_FILE_NAME)) -lstdc++ -APP_LD_ARGS += $(ESPCOMP)/newlib/lib/libc.a -APP_LD_ARGS += $(ESPCOMP)/newlib/lib/libm.a +APP_LD_ARGS += $(LIBC_LIBM) APP_LD_ARGS += $(ESPCOMP)/esp32/libhal.a APP_LD_ARGS += -L$(ESPCOMP)/esp32/lib -lcore -lnet80211 -lphy -lrtc -lpp -lwpa -lsmartconfig -lcoexist -lwps -lwpa2 APP_LD_ARGS += $(OBJ) diff --git a/ports/esp32/README.md b/ports/esp32/README.md index 25407b834a..85df001e3f 100644 --- a/ports/esp32/README.md +++ b/ports/esp32/README.md @@ -78,6 +78,7 @@ ESPIDF = #FLASH_MODE = qio #FLASH_SIZE = 4MB #CROSS_COMPILE = xtensa-esp32-elf- +#CONFIG_SPIRAM_SUPPORT = 1 include Makefile ``` diff --git a/ports/esp32/sdkconfig.h b/ports/esp32/sdkconfig.h index 576f1734a8..f85257a192 100644 --- a/ports/esp32/sdkconfig.h +++ b/ports/esp32/sdkconfig.h @@ -47,6 +47,19 @@ #define CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT 5 #define CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT 2048 +#if CONFIG_SPIRAM_SUPPORT +#define CONFIG_SPIRAM_TYPE_ESPPSRAM32 1 +#define CONFIG_SPIRAM_SIZE 4194304 +#define CONFIG_SPIRAM_SPEED_40M 1 +#define CONFIG_SPIRAM_CACHE_WORKAROUND 1 +#define CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL 16384 +#define CONFIG_SPIRAM_BOOT_INIT 1 +#define CONFIG_SPIRAM_MEMTEST 1 +#define CONFIG_SPIRAM_USE_MALLOC 1 +#define CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL 32768 +#define CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY 1 +#endif + #define CONFIG_FOUR_MAC_ADDRESS_FROM_EFUSE 1 #define CONFIG_DMA_RX_BUF_NUM 10 #define CONFIG_DMA_TX_BUF_NUM 10 From aace60a75e5afedadfc30d33e91ef7c6fa312405 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 5 Jun 2018 14:30:35 +1000 Subject: [PATCH 749/828] esp8266/modules/ntptime.py: Remove print of newly-set time. It should be up to the user if they want to print the new time out or not. Fixes issue #3766. --- ports/esp8266/modules/ntptime.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/esp8266/modules/ntptime.py b/ports/esp8266/modules/ntptime.py index a97e08e60d..85c754af6c 100644 --- a/ports/esp8266/modules/ntptime.py +++ b/ports/esp8266/modules/ntptime.py @@ -33,4 +33,3 @@ def settime(): tm = utime.localtime(t) tm = tm[0:3] + (0,) + tm[3:6] + (0,) machine.RTC().datetime(tm) - print(utime.localtime()) From 172c23fe5d2efd464433c1d80304b8f3d54e7961 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 Jun 2018 11:57:01 +1000 Subject: [PATCH 750/828] extmod/vfs: Use u_rom_obj properly in argument structures. --- extmod/vfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extmod/vfs.c b/extmod/vfs.c index 16f75aba9a..7298edab17 100644 --- a/extmod/vfs.c +++ b/extmod/vfs.c @@ -155,8 +155,8 @@ mp_import_stat_t mp_vfs_import_stat(const char *path) { mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_readonly, ARG_mkfs }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_false} }, - { MP_QSTR_mkfs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_false} }, + { MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_false_obj)} }, + { MP_QSTR_mkfs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_false_obj)} }, }; // parse args @@ -264,7 +264,7 @@ mp_obj_t mp_vfs_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - mp_vfs_mount_t *vfs = lookup_path((mp_obj_t)args[ARG_file].u_rom_obj, &args[ARG_file].u_obj); + mp_vfs_mount_t *vfs = lookup_path(args[ARG_file].u_obj, &args[ARG_file].u_obj); return mp_vfs_proxy_call(vfs, MP_QSTR_open, 2, (mp_obj_t*)&args); } MP_DEFINE_CONST_FUN_OBJ_KW(mp_vfs_open_obj, 0, mp_vfs_open); From f35aae366c4fd54a166960f830b4f93608d847cb Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 Jun 2018 12:00:23 +1000 Subject: [PATCH 751/828] extmod/vfs_fat: Rename FileIO/TextIO types to mp_type_vfs_fat_XXX. So they don't clash with other VFS implementations. --- extmod/vfs_fat.h | 2 ++ extmod/vfs_fat_file.c | 16 +++++----------- ports/cc3200/mpconfigport.h | 4 ++-- ports/esp32/mpconfigport.h | 4 ++-- ports/esp8266/mpconfigport.h | 4 ++-- ports/stm32/mpconfigport.h | 4 ++-- 6 files changed, 15 insertions(+), 19 deletions(-) diff --git a/extmod/vfs_fat.h b/extmod/vfs_fat.h index da56a90770..e0836a555b 100644 --- a/extmod/vfs_fat.h +++ b/extmod/vfs_fat.h @@ -55,6 +55,8 @@ typedef struct _fs_user_mount_t { extern const byte fresult_to_errno_table[20]; extern const mp_obj_type_t mp_fat_vfs_type; +extern const mp_obj_type_t mp_type_vfs_fat_fileio; +extern const mp_obj_type_t mp_type_vfs_fat_textio; mp_import_stat_t fat_vfs_import_stat(struct _fs_user_mount_t *vfs, const char *path); MP_DECLARE_CONST_FUN_OBJ_3(fat_vfs_open_obj); diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c index cbd013f160..f7b9331b82 100644 --- a/extmod/vfs_fat_file.c +++ b/extmod/vfs_fat_file.c @@ -35,12 +35,6 @@ #include "lib/oofatfs/ff.h" #include "extmod/vfs_fat.h" -#define mp_type_fileio fatfs_type_fileio -#define mp_type_textio fatfs_type_textio - -extern const mp_obj_type_t mp_type_fileio; -extern const mp_obj_type_t mp_type_textio; - // this table converts from FRESULT to POSIX errno const byte fresult_to_errno_table[20] = { [FR_OK] = 0, @@ -189,11 +183,11 @@ STATIC mp_obj_t file_open(fs_user_mount_t *vfs, const mp_obj_type_t *type, mp_ar break; #if MICROPY_PY_IO_FILEIO case 'b': - type = &mp_type_fileio; + type = &mp_type_vfs_fat_fileio; break; #endif case 't': - type = &mp_type_textio; + type = &mp_type_vfs_fat_textio; break; } } @@ -249,7 +243,7 @@ STATIC const mp_stream_p_t fileio_stream_p = { .ioctl = file_obj_ioctl, }; -const mp_obj_type_t mp_type_fileio = { +const mp_obj_type_t mp_type_vfs_fat_fileio = { { &mp_type_type }, .name = MP_QSTR_FileIO, .print = file_obj_print, @@ -268,7 +262,7 @@ STATIC const mp_stream_p_t textio_stream_p = { .is_text = true, }; -const mp_obj_type_t mp_type_textio = { +const mp_obj_type_t mp_type_vfs_fat_textio = { { &mp_type_type }, .name = MP_QSTR_TextIOWrapper, .print = file_obj_print, @@ -287,7 +281,7 @@ STATIC mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_ arg_vals[0].u_obj = path; arg_vals[1].u_obj = mode; arg_vals[2].u_obj = mp_const_none; - return file_open(self, &mp_type_textio, arg_vals); + return file_open(self, &mp_type_vfs_fat_textio, arg_vals); } MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_open_obj, fatfs_builtin_open_self); diff --git a/ports/cc3200/mpconfigport.h b/ports/cc3200/mpconfigport.h index 29ae9092b1..ee9a226e5c 100644 --- a/ports/cc3200/mpconfigport.h +++ b/ports/cc3200/mpconfigport.h @@ -131,8 +131,8 @@ X(ETIMEDOUT) \ // TODO these should be generic, not bound to fatfs -#define mp_type_fileio fatfs_type_fileio -#define mp_type_textio fatfs_type_textio +#define mp_type_fileio mp_type_vfs_fat_fileio +#define mp_type_textio mp_type_vfs_fat_textio // use vfs's functions for import stat and builtin open #define mp_import_stat mp_vfs_import_stat diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index c7a87e3afe..24034ba16c 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -152,8 +152,8 @@ #define MICROPY_FATFS_RPATH (2) #define MICROPY_FATFS_MAX_SS (4096) #define MICROPY_FATFS_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ -#define mp_type_fileio fatfs_type_fileio -#define mp_type_textio fatfs_type_textio +#define mp_type_fileio mp_type_vfs_fat_fileio +#define mp_type_textio mp_type_vfs_fat_textio // use vfs's functions for import stat and builtin open #define mp_import_stat mp_vfs_import_stat diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index f29dbe5c02..ff45f86aeb 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -141,8 +141,8 @@ typedef uint32_t sys_prot_t; // for modlwip void *esp_native_code_commit(void*, size_t); #define MP_PLAT_COMMIT_EXEC(buf, len) esp_native_code_commit(buf, len) -#define mp_type_fileio fatfs_type_fileio -#define mp_type_textio fatfs_type_textio +#define mp_type_fileio mp_type_vfs_fat_fileio +#define mp_type_textio mp_type_vfs_fat_textio // use vfs's functions for import stat and builtin open #define mp_import_stat mp_vfs_import_stat diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 7bd9442131..ecb3596fff 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -161,8 +161,8 @@ #define MICROPY_FATFS_MULTI_PARTITION (1) // TODO these should be generic, not bound to fatfs -#define mp_type_fileio fatfs_type_fileio -#define mp_type_textio fatfs_type_textio +#define mp_type_fileio mp_type_vfs_fat_fileio +#define mp_type_textio mp_type_vfs_fat_textio // use vfs's functions for import stat and builtin open #define mp_import_stat mp_vfs_import_stat From 8d82b0edbd38cd6019ec1c55dbc886c9058be7d4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 Jun 2018 13:11:33 +1000 Subject: [PATCH 752/828] extmod: Add VfsPosix filesystem component. This VFS component allows to mount a host POSIX filesystem within the uPy VFS sub-system. All traditional POSIX file access then goes through the VFS, allowing to sandbox a uPy process to a certain sub-dir of the host system, as well as mount other filesystem types alongside the host filesystem. --- extmod/vfs_posix.c | 357 ++++++++++++++++++++++++++++++++++++++++ extmod/vfs_posix.h | 41 +++++ extmod/vfs_posix_file.c | 261 +++++++++++++++++++++++++++++ py/mpconfig.h | 5 + py/py.mk | 2 + 5 files changed, 666 insertions(+) create mode 100644 extmod/vfs_posix.c create mode 100644 extmod/vfs_posix.h create mode 100644 extmod/vfs_posix_file.c diff --git a/extmod/vfs_posix.c b/extmod/vfs_posix.c new file mode 100644 index 0000000000..0db45a0c1f --- /dev/null +++ b/extmod/vfs_posix.c @@ -0,0 +1,357 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "extmod/vfs.h" +#include "extmod/vfs_posix.h" + +#if MICROPY_VFS_POSIX + +#include +#include +#include + +typedef struct _mp_obj_vfs_posix_t { + mp_obj_base_t base; + vstr_t root; + size_t root_len; + bool readonly; +} mp_obj_vfs_posix_t; + +STATIC const char *vfs_posix_get_path_str(mp_obj_vfs_posix_t *self, mp_obj_t path) { + if (self->root_len == 0) { + return mp_obj_str_get_str(path); + } else { + self->root.len = self->root_len; + vstr_add_str(&self->root, mp_obj_str_get_str(path)); + return vstr_null_terminated_str(&self->root); + } +} + +STATIC mp_obj_t vfs_posix_get_path_obj(mp_obj_vfs_posix_t *self, mp_obj_t path) { + if (self->root_len == 0) { + return path; + } else { + self->root.len = self->root_len; + vstr_add_str(&self->root, mp_obj_str_get_str(path)); + return mp_obj_new_str(self->root.buf, self->root.len); + } +} + +STATIC mp_obj_t vfs_posix_fun1_helper(mp_obj_t self_in, mp_obj_t path_in, int (*f)(const char*)) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + int ret = f(vfs_posix_get_path_str(self, path_in)); + if (ret != 0) { + mp_raise_OSError(errno); + } + return mp_const_none; +} + +mp_import_stat_t mp_vfs_posix_import_stat(mp_obj_vfs_posix_t *self, const char *path) { + if (self->root_len != 0) { + self->root.len = self->root_len; + vstr_add_str(&self->root, path); + path = vstr_null_terminated_str(&self->root); + } + struct stat st; + if (stat(path, &st) == 0) { + if (S_ISDIR(st.st_mode)) { + return MP_IMPORT_STAT_DIR; + } else if (S_ISREG(st.st_mode)) { + return MP_IMPORT_STAT_FILE; + } + } + return MP_IMPORT_STAT_NO_EXIST; +} + +STATIC mp_obj_t vfs_posix_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + + mp_obj_vfs_posix_t *vfs = m_new_obj(mp_obj_vfs_posix_t); + vfs->base.type = type; + vstr_init(&vfs->root, 0); + if (n_args == 1) { + vstr_add_str(&vfs->root, mp_obj_str_get_str(args[0])); + vstr_add_char(&vfs->root, '/'); + } + vfs->root_len = vfs->root.len; + vfs->readonly = false; + + return MP_OBJ_FROM_PTR(vfs); +} + +STATIC mp_obj_t vfs_posix_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + if (mp_obj_is_true(readonly)) { + self->readonly = true; + } + if (mp_obj_is_true(mkfs)) { + mp_raise_OSError(MP_EPERM); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_mount_obj, vfs_posix_mount); + +STATIC mp_obj_t vfs_posix_umount(mp_obj_t self_in) { + (void)self_in; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_umount_obj, vfs_posix_umount); + +STATIC mp_obj_t vfs_posix_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + const char *mode = mp_obj_str_get_str(mode_in); + if (self->readonly + && (strchr(mode, 'w') != NULL || strchr(mode, 'a') != NULL || strchr(mode, '+') != NULL)) { + mp_raise_OSError(MP_EROFS); + } + if (!MP_OBJ_IS_SMALL_INT(path_in)) { + path_in = vfs_posix_get_path_obj(self, path_in); + } + return mp_vfs_posix_file_open(&mp_type_textio, path_in, mode_in); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_open_obj, vfs_posix_open); + +STATIC mp_obj_t vfs_posix_chdir(mp_obj_t self_in, mp_obj_t path_in) { + return vfs_posix_fun1_helper(self_in, path_in, chdir); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_chdir_obj, vfs_posix_chdir); + +STATIC mp_obj_t vfs_posix_getcwd(mp_obj_t self_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + char buf[MICROPY_ALLOC_PATH_MAX + 1]; + const char *ret = getcwd(buf, sizeof(buf)); + if (ret == NULL) { + mp_raise_OSError(errno); + } + ret += self->root_len; + return mp_obj_new_str(ret, strlen(ret)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_getcwd_obj, vfs_posix_getcwd); + +typedef struct _vfs_posix_ilistdir_it_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + bool is_str; + DIR *dir; +} vfs_posix_ilistdir_it_t; + +STATIC mp_obj_t vfs_posix_ilistdir_it_iternext(mp_obj_t self_in) { + vfs_posix_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->dir == NULL) { + return MP_OBJ_STOP_ITERATION; + } + + for (;;) { + struct dirent *dirent = readdir(self->dir); + if (dirent == NULL) { + closedir(self->dir); + self->dir = NULL; + return MP_OBJ_STOP_ITERATION; + } + const char *fn = dirent->d_name; + + if (fn[0] == '.' && (fn[1] == 0 || fn[1] == '.')) { + // skip . and .. + continue; + } + + // make 3-tuple with info about this entry + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); + + if (self->is_str) { + t->items[0] = mp_obj_new_str(fn, strlen(fn)); + } else { + t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn)); + } + + #ifdef _DIRENT_HAVE_D_TYPE + if (dirent->d_type == DT_DIR) { + t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR); + } else if (dirent->d_type == DT_REG) { + t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG); + } else { + t->items[1] = MP_OBJ_NEW_SMALL_INT(dirent->d_type); + } + #else + // DT_UNKNOWN should have 0 value on any reasonable system + t->items[1] = MP_OBJ_NEW_SMALL_INT(0); + #endif + #ifdef _DIRENT_HAVE_D_INO + t->items[2] = MP_OBJ_NEW_SMALL_INT(dirent->d_ino); + #else + t->items[2] = MP_OBJ_NEW_SMALL_INT(0); + #endif + + return MP_OBJ_FROM_PTR(t); + } +} + +STATIC mp_obj_t vfs_posix_ilistdir(mp_obj_t self_in, mp_obj_t path_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + vfs_posix_ilistdir_it_t *iter = m_new_obj(vfs_posix_ilistdir_it_t); + iter->base.type = &mp_type_polymorph_iter; + iter->iternext = vfs_posix_ilistdir_it_iternext; + iter->is_str = mp_obj_get_type(path_in) == &mp_type_str; + const char *path = vfs_posix_get_path_str(self, path_in); + iter->dir = opendir(path); + if (iter->dir == NULL) { + mp_raise_OSError(errno); + } + return MP_OBJ_FROM_PTR(iter); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_ilistdir_obj, vfs_posix_ilistdir); + +typedef struct _mp_obj_listdir_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + DIR *dir; +} mp_obj_listdir_t; + +STATIC mp_obj_t vfs_posix_mkdir(mp_obj_t self_in, mp_obj_t path_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + int ret = mkdir(vfs_posix_get_path_str(self, path_in), 0777); + if (ret != 0) { + mp_raise_OSError(errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_mkdir_obj, vfs_posix_mkdir); + +STATIC mp_obj_t vfs_posix_remove(mp_obj_t self_in, mp_obj_t path_in) { + return vfs_posix_fun1_helper(self_in, path_in, unlink); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_remove_obj, vfs_posix_remove); + +STATIC mp_obj_t vfs_posix_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_t new_path_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + const char *old_path = vfs_posix_get_path_str(self, old_path_in); + const char *new_path = vfs_posix_get_path_str(self, new_path_in); + int ret = rename(old_path, new_path); + if (ret != 0) { + mp_raise_OSError(errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_rename_obj, vfs_posix_rename); + +STATIC mp_obj_t vfs_posix_rmdir(mp_obj_t self_in, mp_obj_t path_in) { + return vfs_posix_fun1_helper(self_in, path_in, rmdir); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_rmdir_obj, vfs_posix_rmdir); + +STATIC mp_obj_t vfs_posix_stat(mp_obj_t self_in, mp_obj_t path_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + struct stat sb; + int ret = stat(vfs_posix_get_path_str(self, path_in), &sb); + if (ret != 0) { + mp_raise_OSError(errno); + } + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); + t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.st_mode); + t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.st_ino); + t->items[2] = MP_OBJ_NEW_SMALL_INT(sb.st_dev); + t->items[3] = MP_OBJ_NEW_SMALL_INT(sb.st_nlink); + t->items[4] = MP_OBJ_NEW_SMALL_INT(sb.st_uid); + t->items[5] = MP_OBJ_NEW_SMALL_INT(sb.st_gid); + t->items[6] = MP_OBJ_NEW_SMALL_INT(sb.st_size); + t->items[7] = MP_OBJ_NEW_SMALL_INT(sb.st_atime); + t->items[8] = MP_OBJ_NEW_SMALL_INT(sb.st_mtime); + t->items[9] = MP_OBJ_NEW_SMALL_INT(sb.st_ctime); + return MP_OBJ_FROM_PTR(t); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_stat_obj, vfs_posix_stat); + +#ifdef __ANDROID__ +#define USE_STATFS 1 +#endif + +#if USE_STATFS +#include +#define STRUCT_STATVFS struct statfs +#define STATVFS statfs +#define F_FAVAIL sb.f_ffree +#define F_NAMEMAX sb.f_namelen +#define F_FLAG sb.f_flags +#else +#include +#define STRUCT_STATVFS struct statvfs +#define STATVFS statvfs +#define F_FAVAIL sb.f_favail +#define F_NAMEMAX sb.f_namemax +#define F_FLAG sb.f_flag +#endif + +STATIC mp_obj_t vfs_posix_statvfs(mp_obj_t self_in, mp_obj_t path_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + STRUCT_STATVFS sb; + const char *path = vfs_posix_get_path_str(self, path_in); + int ret = STATVFS(path, &sb); + if (ret != 0) { + mp_raise_OSError(errno); + } + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); + t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.f_bsize); + t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.f_frsize); + t->items[2] = MP_OBJ_NEW_SMALL_INT(sb.f_blocks); + t->items[3] = MP_OBJ_NEW_SMALL_INT(sb.f_bfree); + t->items[4] = MP_OBJ_NEW_SMALL_INT(sb.f_bavail); + t->items[5] = MP_OBJ_NEW_SMALL_INT(sb.f_files); + t->items[6] = MP_OBJ_NEW_SMALL_INT(sb.f_ffree); + t->items[7] = MP_OBJ_NEW_SMALL_INT(F_FAVAIL); + t->items[8] = MP_OBJ_NEW_SMALL_INT(F_FLAG); + t->items[9] = MP_OBJ_NEW_SMALL_INT(F_NAMEMAX); + return MP_OBJ_FROM_PTR(t); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_statvfs_obj, vfs_posix_statvfs); + +STATIC const mp_rom_map_elem_t vfs_posix_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&vfs_posix_mount_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&vfs_posix_umount_obj) }, + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&vfs_posix_open_obj) }, + + { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&vfs_posix_chdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&vfs_posix_getcwd_obj) }, + { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&vfs_posix_ilistdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&vfs_posix_mkdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&vfs_posix_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&vfs_posix_rename_obj) }, + { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&vfs_posix_rmdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&vfs_posix_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&vfs_posix_statvfs_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(vfs_posix_locals_dict, vfs_posix_locals_dict_table); + +const mp_obj_type_t mp_type_vfs_posix = { + { &mp_type_type }, + .name = MP_QSTR_VfsPosix, + .make_new = vfs_posix_make_new, + .locals_dict = (mp_obj_dict_t*)&vfs_posix_locals_dict, +}; + +#endif // MICROPY_VFS_POSIX diff --git a/extmod/vfs_posix.h b/extmod/vfs_posix.h new file mode 100644 index 0000000000..35a255ff62 --- /dev/null +++ b/extmod/vfs_posix.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H +#define MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H + +#include "py/lexer.h" +#include "py/obj.h" + +struct _mp_obj_vfs_posix_t; + +extern const mp_obj_type_t mp_type_vfs_posix; +extern const mp_obj_type_t mp_type_vfs_posix_fileio; +extern const mp_obj_type_t mp_type_vfs_posix_textio; + +mp_import_stat_t mp_vfs_posix_import_stat(struct _mp_obj_vfs_posix_t *self, const char *path_in); +mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_obj_t mode_in); + +#endif // MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c new file mode 100644 index 0000000000..435ac65cd4 --- /dev/null +++ b/extmod/vfs_posix_file.c @@ -0,0 +1,261 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/stream.h" +#include "extmod/vfs_posix.h" + +#if MICROPY_VFS_POSIX + +#include + +#ifdef _WIN32 +#define fsync _commit +#endif + +typedef struct _mp_obj_vfs_posix_file_t { + mp_obj_base_t base; + int fd; +} mp_obj_vfs_posix_file_t; + +#ifdef MICROPY_CPYTHON_COMPAT +STATIC void check_fd_is_open(const mp_obj_vfs_posix_file_t *o) { + if (o->fd < 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "I/O operation on closed file")); + } +} +#else +#define check_fd_is_open(o) +#endif + +STATIC void vfs_posix_file_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_vfs_posix_file_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", mp_obj_get_type_str(self_in), self->fd); +} + +mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_obj_t mode_in) { + mp_obj_vfs_posix_file_t *o = m_new_obj(mp_obj_vfs_posix_file_t); + const char *mode_s = mp_obj_str_get_str(mode_in); + + int mode_rw = 0, mode_x = 0; + while (*mode_s) { + switch (*mode_s++) { + case 'r': + mode_rw = O_RDONLY; + break; + case 'w': + mode_rw = O_WRONLY; + mode_x = O_CREAT | O_TRUNC; + break; + case 'a': + mode_rw = O_WRONLY; + mode_x = O_CREAT | O_APPEND; + break; + case '+': + mode_rw = O_RDWR; + break; + #if MICROPY_PY_IO_FILEIO + // If we don't have io.FileIO, then files are in text mode implicitly + case 'b': + type = &mp_type_vfs_posix_fileio; + break; + case 't': + type = &mp_type_vfs_posix_textio; + break; + #endif + } + } + + o->base.type = type; + + mp_obj_t fid = file_in; + + if (MP_OBJ_IS_SMALL_INT(fid)) { + o->fd = MP_OBJ_SMALL_INT_VALUE(fid); + return MP_OBJ_FROM_PTR(o); + } + + const char *fname = mp_obj_str_get_str(fid); + int fd = open(fname, mode_x | mode_rw, 0644); + if (fd == -1) { + mp_raise_OSError(errno); + } + o->fd = fd; + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t vfs_posix_file_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} }, + }; + + mp_arg_val_t arg_vals[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, arg_vals); + return mp_vfs_posix_file_open(type, arg_vals[0].u_obj, arg_vals[1].u_obj); +} + +STATIC mp_obj_t vfs_posix_file_fileno(mp_obj_t self_in) { + mp_obj_vfs_posix_file_t *self = MP_OBJ_TO_PTR(self_in); + check_fd_is_open(self); + return MP_OBJ_NEW_SMALL_INT(self->fd); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_file_fileno_obj, vfs_posix_file_fileno); + +STATIC mp_obj_t vfs_posix_file___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + return mp_stream_close(args[0]); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(vfs_posix_file___exit___obj, 4, 4, vfs_posix_file___exit__); + +STATIC mp_uint_t vfs_posix_file_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { + mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in); + check_fd_is_open(o); + mp_int_t r = read(o->fd, buf, size); + if (r == -1) { + *errcode = errno; + return MP_STREAM_ERROR; + } + return r; +} + +STATIC mp_uint_t vfs_posix_file_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { + mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in); + check_fd_is_open(o); + #if MICROPY_PY_OS_DUPTERM + if (o->fd <= STDERR_FILENO) { + mp_hal_stdout_tx_strn(buf, size); + return size; + } + #endif + mp_int_t r = write(o->fd, buf, size); + while (r == -1 && errno == EINTR) { + if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { + mp_obj_t obj = MP_STATE_VM(mp_pending_exception); + MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + nlr_raise(obj); + } + r = write(o->fd, buf, size); + } + if (r == -1) { + *errcode = errno; + return MP_STREAM_ERROR; + } + return r; +} + +STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in); + check_fd_is_open(o); + switch (request) { + case MP_STREAM_FLUSH: + if (fsync(o->fd) < 0) { + *errcode = errno; + return MP_STREAM_ERROR; + } + return 0; + case MP_STREAM_SEEK: { + struct mp_stream_seek_t *s = (struct mp_stream_seek_t*)arg; + off_t off = lseek(o->fd, s->offset, s->whence); + if (off == (off_t)-1) { + *errcode = errno; + return MP_STREAM_ERROR; + } + s->offset = off; + return 0; + } + case MP_STREAM_CLOSE: + close(o->fd); + #ifdef MICROPY_CPYTHON_COMPAT + o->fd = -1; + #endif + return 0; + default: + *errcode = EINVAL; + return MP_STREAM_ERROR; + } +} + +STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_fileno), MP_ROM_PTR(&vfs_posix_file_fileno_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) }, + { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) }, + { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&vfs_posix_file___exit___obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table); + +#if MICROPY_PY_IO_FILEIO +STATIC const mp_stream_p_t fileio_stream_p = { + .read = vfs_posix_file_read, + .write = vfs_posix_file_write, + .ioctl = vfs_posix_file_ioctl, +}; + +const mp_obj_type_t mp_type_vfs_posix_fileio = { + { &mp_type_type }, + .name = MP_QSTR_FileIO, + .print = vfs_posix_file_print, + .make_new = vfs_posix_file_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &fileio_stream_p, + .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, +}; +#endif + +STATIC const mp_stream_p_t textio_stream_p = { + .read = vfs_posix_file_read, + .write = vfs_posix_file_write, + .ioctl = vfs_posix_file_ioctl, + .is_text = true, +}; + +const mp_obj_type_t mp_type_vfs_posix_textio = { + { &mp_type_type }, + .name = MP_QSTR_TextIOWrapper, + .print = vfs_posix_file_print, + .make_new = vfs_posix_file_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &textio_stream_p, + .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, +}; + +const mp_obj_vfs_posix_file_t mp_sys_stdin_obj = {{&mp_type_textio}, STDIN_FILENO}; +const mp_obj_vfs_posix_file_t mp_sys_stdout_obj = {{&mp_type_textio}, STDOUT_FILENO}; +const mp_obj_vfs_posix_file_t mp_sys_stderr_obj = {{&mp_type_textio}, STDERR_FILENO}; + +#endif // MICROPY_VFS_POSIX diff --git a/py/mpconfig.h b/py/mpconfig.h index 100e2a9810..dc0fc5d40e 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -681,6 +681,11 @@ typedef double mp_float_t; #define MICROPY_VFS (0) #endif +// Support for VFS POSIX component, to mount a POSIX filesystem within VFS +#ifndef MICROPY_VFS +#define MICROPY_VFS_POSIX (0) +#endif + /*****************************************************************************/ /* Fine control over Python builtins, classes, modules, etc */ diff --git a/py/py.mk b/py/py.mk index a918135268..f4b62a88af 100644 --- a/py/py.mk +++ b/py/py.mk @@ -241,6 +241,8 @@ PY_EXTMOD_O_BASENAME = \ extmod/modframebuf.o \ extmod/vfs.o \ extmod/vfs_reader.o \ + extmod/vfs_posix.o \ + extmod/vfs_posix_file.o \ extmod/vfs_fat.o \ extmod/vfs_fat_diskio.o \ extmod/vfs_fat_file.o \ From a93144cb65c4e68cba137aa82413c56e0a409d81 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 Jun 2018 13:12:05 +1000 Subject: [PATCH 753/828] py/reader: Allow MICROPY_VFS_POSIX to work with MICROPY_READER_POSIX. --- py/reader.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/py/reader.c b/py/reader.c index c4d18d53dc..80364104bb 100644 --- a/py/reader.c +++ b/py/reader.c @@ -124,6 +124,8 @@ void mp_reader_new_file_from_fd(mp_reader_t *reader, int fd, bool close_fd) { reader->close = mp_reader_posix_close; } +#if !MICROPY_VFS_POSIX +// If MICROPY_VFS_POSIX is defined then this function is provided by the VFS layer void mp_reader_new_file(mp_reader_t *reader, const char *filename) { int fd = open(filename, O_RDONLY, 0644); if (fd < 0) { @@ -131,5 +133,6 @@ void mp_reader_new_file(mp_reader_t *reader, const char *filename) { } mp_reader_new_file_from_fd(reader, fd, true); } +#endif #endif From d4ce57e4e320a717db1a231f2e6c1e92afaafde0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 Jun 2018 13:12:23 +1000 Subject: [PATCH 754/828] extmod/vfs: Add fast path for stating VfsPosix filesystem. --- extmod/vfs.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/extmod/vfs.c b/extmod/vfs.c index 7298edab17..96d5019b37 100644 --- a/extmod/vfs.c +++ b/extmod/vfs.c @@ -34,6 +34,9 @@ #if MICROPY_VFS +#if MICROPY_VFS_POSIX +#include "extmod/vfs_posix.h" +#endif #if MICROPY_VFS_FAT #include "extmod/vfs_fat.h" #endif @@ -124,8 +127,14 @@ mp_import_stat_t mp_vfs_import_stat(const char *path) { if (vfs == MP_VFS_NONE || vfs == MP_VFS_ROOT) { return MP_IMPORT_STAT_NO_EXIST; } + + // Fast paths for known VFS types + #if MICROPY_VFS_POSIX + if (mp_obj_get_type(vfs->obj) == &mp_type_vfs_posix) { + return mp_vfs_posix_import_stat(MP_OBJ_TO_PTR(vfs->obj), path_out); + } + #endif #if MICROPY_VFS_FAT - // fast paths for known VFS types if (mp_obj_get_type(vfs->obj) == &mp_fat_vfs_type) { return fat_vfs_import_stat(MP_OBJ_TO_PTR(vfs->obj), path_out); } From 1d40f12e44afcd0ac13fd78598098298831e254e Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 Jun 2018 13:15:04 +1000 Subject: [PATCH 755/828] unix: Support MICROPY_VFS_POSIX and enable it in coverage build. The unix coverage build is now switched fully to the VFS implementation, ie the uos module is the uos_vfs module. For example, one can now sandbox uPy to their home directory via: $ ./micropython_coverage >>> import uos >>> uos.umount('/') # unmount existing root VFS >>> vfs = uos.VfsPosix('/home/user') # create new POSIX VFS >>> uos.mount(vfs, '/') # mount new POSIX VFS at root Some filesystem/OS features may no longer work with the coverage build due to this change, and these need to be gradually fixed. The standard unix port remains unchanged, it still uses the traditional uos module which directly accesses the underlying host filesystem. --- ports/unix/file.c | 4 ++-- ports/unix/main.c | 16 ++++++++++++++++ ports/unix/moduos_vfs.c | 4 ++++ ports/unix/mpconfigport.h | 7 +++---- ports/unix/mpconfigport_coverage.h | 11 +++++++++++ 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/ports/unix/file.c b/ports/unix/file.c index 9bb44c6abd..165bbd00b0 100644 --- a/ports/unix/file.c +++ b/ports/unix/file.c @@ -37,7 +37,7 @@ #include "py/mphal.h" #include "fdfile.h" -#if MICROPY_PY_IO +#if MICROPY_PY_IO && !MICROPY_VFS #ifdef _WIN32 #define fsync _commit @@ -277,4 +277,4 @@ const mp_obj_fdfile_t mp_sys_stdin_obj = { .base = {&mp_type_textio}, .fd = STD const mp_obj_fdfile_t mp_sys_stdout_obj = { .base = {&mp_type_textio}, .fd = STDOUT_FILENO }; const mp_obj_fdfile_t mp_sys_stderr_obj = { .base = {&mp_type_textio}, .fd = STDERR_FILENO }; -#endif // MICROPY_PY_IO +#endif // MICROPY_PY_IO && !MICROPY_VFS diff --git a/ports/unix/main.c b/ports/unix/main.c index 03f2f357ee..b68fe92797 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -46,6 +46,8 @@ #include "py/mphal.h" #include "py/mpthread.h" #include "extmod/misc.h" +#include "extmod/vfs.h" +#include "extmod/vfs_posix.h" #include "genhdr/mpversion.h" #include "input.h" @@ -447,6 +449,18 @@ MP_NOINLINE int main_(int argc, char **argv) { mp_init(); + #if MICROPY_VFS_POSIX + { + // Mount the host FS at the root of our internal VFS + mp_obj_t args[2] = { + mp_type_vfs_posix.make_new(&mp_type_vfs_posix, 0, 0, NULL), + MP_OBJ_NEW_QSTR(MP_QSTR__slash_), + }; + mp_vfs_mount(2, args, (mp_map_t*)&mp_const_empty_map); + MP_STATE_VM(vfs_cur) = MP_STATE_VM(vfs_mount_table); + } + #endif + char *home = getenv("HOME"); char *path = getenv("MICROPYPATH"); if (path == NULL) { @@ -645,6 +659,7 @@ MP_NOINLINE int main_(int argc, char **argv) { return ret & 0xff; } +#if !MICROPY_VFS uint mp_import_stat(const char *path) { struct stat st; if (stat(path, &st) == 0) { @@ -656,6 +671,7 @@ uint mp_import_stat(const char *path) { } return MP_IMPORT_STAT_NO_EXIST; } +#endif void nlr_jump_fail(void *val) { printf("FATAL: uncaught NLR %p\n", val); diff --git a/ports/unix/moduos_vfs.c b/ports/unix/moduos_vfs.c index 96defa5544..c61471e582 100644 --- a/ports/unix/moduos_vfs.c +++ b/ports/unix/moduos_vfs.c @@ -28,6 +28,7 @@ #include #include "extmod/vfs.h" +#include "extmod/vfs_posix.h" #include "extmod/vfs_fat.h" #if MICROPY_VFS @@ -52,6 +53,9 @@ STATIC const mp_rom_map_elem_t uos_vfs_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) }, { MP_ROM_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&mp_vfs_remove_obj) }, // unlink aliases to remove + #if MICROPY_VFS_POSIX + { MP_ROM_QSTR(MP_QSTR_VfsPosix), MP_ROM_PTR(&mp_type_vfs_posix) }, + #endif #if MICROPY_VFS_FAT { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, #endif diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index f0e17ccad0..016dabf9f4 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -180,9 +180,9 @@ extern const struct _mp_obj_module_t mp_module_ffi; extern const struct _mp_obj_module_t mp_module_jni; #if MICROPY_PY_UOS_VFS -#define MICROPY_PY_UOS_VFS_DEF { MP_ROM_QSTR(MP_QSTR_uos_vfs), MP_ROM_PTR(&mp_module_uos_vfs) }, +#define MICROPY_PY_UOS_DEF { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos_vfs) }, #else -#define MICROPY_PY_UOS_VFS_DEF +#define MICROPY_PY_UOS_DEF { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_os) }, #endif #if MICROPY_PY_FFI #define MICROPY_PY_FFI_DEF { MP_ROM_QSTR(MP_QSTR_ffi), MP_ROM_PTR(&mp_module_ffi) }, @@ -221,8 +221,7 @@ extern const struct _mp_obj_module_t mp_module_jni; MICROPY_PY_UTIME_DEF \ MICROPY_PY_SOCKET_DEF \ { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&mp_module_machine) }, \ - { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_os) }, \ - MICROPY_PY_UOS_VFS_DEF \ + MICROPY_PY_UOS_DEF \ MICROPY_PY_USELECT_DEF \ MICROPY_PY_TERMIOS_DEF \ diff --git a/ports/unix/mpconfigport_coverage.h b/ports/unix/mpconfigport_coverage.h index b3fcd1e6b0..f0e6fbe94b 100644 --- a/ports/unix/mpconfigport_coverage.h +++ b/ports/unix/mpconfigport_coverage.h @@ -34,6 +34,7 @@ #define MICROPY_FLOAT_HIGH_QUALITY_HASH (1) #define MICROPY_ENABLE_SCHEDULER (1) +#define MICROPY_READER_VFS (1) #define MICROPY_PY_DELATTR_SETATTR (1) #define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) #define MICROPY_PY_BUILTINS_RANGE_BINOP (1) @@ -43,7 +44,17 @@ #define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) #define MICROPY_PY_IO_BUFFEREDWRITER (1) #define MICROPY_PY_IO_RESOURCE_STREAM (1) +#define MICROPY_VFS_POSIX (1) #undef MICROPY_VFS_FAT #define MICROPY_VFS_FAT (1) #define MICROPY_PY_FRAMEBUF (1) #define MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT (1) + +// TODO these should be generic, not bound to fatfs +#define mp_type_fileio mp_type_vfs_posix_fileio +#define mp_type_textio mp_type_vfs_posix_textio + +// use vfs's functions for import stat and builtin open +#define mp_import_stat mp_vfs_import_stat +#define mp_builtin_open mp_vfs_open +#define mp_builtin_open_obj mp_vfs_open_obj From 6c02da2eec02fc51c74dc6bfb9aeb34428c7a85e Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 Jun 2018 13:22:51 +1000 Subject: [PATCH 756/828] tests/extmod: Add test for importing a script from a user VFS. --- tests/extmod/vfs_fat_more.py | 8 ++++++++ tests/extmod/vfs_fat_more.py.exp | 1 + 2 files changed, 9 insertions(+) diff --git a/tests/extmod/vfs_fat_more.py b/tests/extmod/vfs_fat_more.py index baec96787b..ae340dde8f 100644 --- a/tests/extmod/vfs_fat_more.py +++ b/tests/extmod/vfs_fat_more.py @@ -114,3 +114,11 @@ uos.umount('/') print(uos.getcwd()) print(uos.listdir()) print(uos.listdir('sys')) + +# test importing a file from a mounted FS +import sys +sys.path.clear() +sys.path.append('/sys') +with open('sys/test_module.py', 'w') as f: + f.write('print("test_module!")') +import test_module diff --git a/tests/extmod/vfs_fat_more.py.exp b/tests/extmod/vfs_fat_more.py.exp index aaca3cc75e..24429ee095 100644 --- a/tests/extmod/vfs_fat_more.py.exp +++ b/tests/extmod/vfs_fat_more.py.exp @@ -26,3 +26,4 @@ mkdir OSError True / ['sys'] [] +test_module! From 5ef0d2ab14e7a1a367695e1bb64300f57871d9a3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 Jun 2018 13:24:09 +1000 Subject: [PATCH 757/828] tests/extmod: Remove conditional import of uos_vfs, it no longer exists. This conditional import was only used to get the tests working on the unix coverage build, which has now switched to use VFS by default so the uos module alone has the required functionality. --- tests/extmod/vfs_basic.py | 6 +----- tests/extmod/vfs_fat_fileio1.py | 6 +----- tests/extmod/vfs_fat_fileio2.py | 6 +----- tests/extmod/vfs_fat_more.py | 6 +----- tests/extmod/vfs_fat_oldproto.py | 5 +---- tests/extmod/vfs_fat_ramdisk.py | 5 +---- 6 files changed, 6 insertions(+), 28 deletions(-) diff --git a/tests/extmod/vfs_basic.py b/tests/extmod/vfs_basic.py index 4fc67d34b2..fbcc92bade 100644 --- a/tests/extmod/vfs_basic.py +++ b/tests/extmod/vfs_basic.py @@ -1,11 +1,7 @@ # test VFS functionality without any particular filesystem type try: - try: - import uos_vfs as uos - open = uos.vfs_open - except ImportError: - import uos + import uos uos.mount except (ImportError, AttributeError): print("SKIP") diff --git a/tests/extmod/vfs_fat_fileio1.py b/tests/extmod/vfs_fat_fileio1.py index f1f4639ab7..51cd765222 100644 --- a/tests/extmod/vfs_fat_fileio1.py +++ b/tests/extmod/vfs_fat_fileio1.py @@ -1,10 +1,6 @@ try: import uerrno - try: - import uos_vfs as uos - open = uos.vfs_open - except ImportError: - import uos + import uos except ImportError: print("SKIP") raise SystemExit diff --git a/tests/extmod/vfs_fat_fileio2.py b/tests/extmod/vfs_fat_fileio2.py index b5adb75c96..9b9a11e435 100644 --- a/tests/extmod/vfs_fat_fileio2.py +++ b/tests/extmod/vfs_fat_fileio2.py @@ -1,10 +1,6 @@ try: import uerrno - try: - import uos_vfs as uos - open = uos.vfs_open - except ImportError: - import uos + import uos except ImportError: print("SKIP") raise SystemExit diff --git a/tests/extmod/vfs_fat_more.py b/tests/extmod/vfs_fat_more.py index ae340dde8f..4384e55cba 100644 --- a/tests/extmod/vfs_fat_more.py +++ b/tests/extmod/vfs_fat_more.py @@ -1,10 +1,6 @@ import uerrno try: - try: - import uos_vfs as uos - open = uos.vfs_open - except ImportError: - import uos + import uos except ImportError: print("SKIP") raise SystemExit diff --git a/tests/extmod/vfs_fat_oldproto.py b/tests/extmod/vfs_fat_oldproto.py index ef4f1da78e..3caaa368db 100644 --- a/tests/extmod/vfs_fat_oldproto.py +++ b/tests/extmod/vfs_fat_oldproto.py @@ -1,9 +1,6 @@ try: import uerrno - try: - import uos_vfs as uos - except ImportError: - import uos + import uos except ImportError: print("SKIP") raise SystemExit diff --git a/tests/extmod/vfs_fat_ramdisk.py b/tests/extmod/vfs_fat_ramdisk.py index 801c697862..f6e5c64df0 100644 --- a/tests/extmod/vfs_fat_ramdisk.py +++ b/tests/extmod/vfs_fat_ramdisk.py @@ -1,9 +1,6 @@ try: import uerrno - try: - import uos_vfs as uos - except ImportError: - import uos + import uos except ImportError: print("SKIP") raise SystemExit From fadd6bbe436df73a8a0d15fa9b7e743707ee7c36 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 Jun 2018 13:32:48 +1000 Subject: [PATCH 758/828] unix/moduos_vfs: Add missing uos functions from traditional uos module. Now that the coverage build has fully switched to the VFS sub-system these functions were no longer available, so add them to the uos_vfs module. Also, vfs_open is no longer needed, it's available as the built-in open. --- ports/unix/modos.c | 6 +++--- ports/unix/moduos_vfs.c | 14 +++++++++++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/ports/unix/modos.c b/ports/unix/modos.c index 808d12adb8..d99d0d62c9 100644 --- a/ports/unix/modos.c +++ b/ports/unix/modos.c @@ -126,7 +126,7 @@ STATIC mp_obj_t mod_os_system(mp_obj_t cmd_in) { return MP_OBJ_NEW_SMALL_INT(r); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_system_obj, mod_os_system); +MP_DEFINE_CONST_FUN_OBJ_1(mod_os_system_obj, mod_os_system); STATIC mp_obj_t mod_os_getenv(mp_obj_t var_in) { const char *s = getenv(mp_obj_str_get_str(var_in)); @@ -135,7 +135,7 @@ STATIC mp_obj_t mod_os_getenv(mp_obj_t var_in) { } return mp_obj_new_str(s, strlen(s)); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_getenv_obj, mod_os_getenv); +MP_DEFINE_CONST_FUN_OBJ_1(mod_os_getenv_obj, mod_os_getenv); STATIC mp_obj_t mod_os_mkdir(mp_obj_t path_in) { // TODO: Accept mode param @@ -207,7 +207,7 @@ STATIC mp_obj_t mod_os_errno(size_t n_args, const mp_obj_t *args) { errno = mp_obj_get_int(args[0]); return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_errno_obj, 0, 1, mod_os_errno); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_errno_obj, 0, 1, mod_os_errno); STATIC const mp_rom_map_elem_t mp_module_os_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, diff --git a/ports/unix/moduos_vfs.c b/ports/unix/moduos_vfs.c index c61471e582..e9ac8e1f88 100644 --- a/ports/unix/moduos_vfs.c +++ b/ports/unix/moduos_vfs.c @@ -33,13 +33,21 @@ #if MICROPY_VFS +// These are defined in modos.c +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_errno_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mod_os_getenv_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mod_os_system_obj); + STATIC const mp_rom_map_elem_t uos_vfs_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos_vfs) }, { MP_ROM_QSTR(MP_QSTR_sep), MP_ROM_QSTR(MP_QSTR__slash_) }, + { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mod_os_errno_obj) }, + { MP_ROM_QSTR(MP_QSTR_getenv), MP_ROM_PTR(&mod_os_getenv_obj) }, + { MP_ROM_QSTR(MP_QSTR_system), MP_ROM_PTR(&mod_os_system_obj) }, + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) }, - { MP_ROM_QSTR(MP_QSTR_vfs_open), MP_ROM_PTR(&mp_vfs_open_obj) }, { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) }, { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) }, @@ -53,6 +61,10 @@ STATIC const mp_rom_map_elem_t uos_vfs_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) }, { MP_ROM_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&mp_vfs_remove_obj) }, // unlink aliases to remove + #if MICROPY_PY_OS_DUPTERM + { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) }, + #endif + #if MICROPY_VFS_POSIX { MP_ROM_QSTR(MP_QSTR_VfsPosix), MP_ROM_PTR(&mp_type_vfs_posix) }, #endif From c117effddd1f9ffd902a9712cf0ae7413696dc66 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 Jun 2018 14:24:23 +1000 Subject: [PATCH 759/828] extmod/vfs: Introduce a C-level VFS protocol, with fast import_stat. Following other C-level protocols, this VFS protocol is added to help abstract away implementation details of the underlying VFS in an efficient way. As a starting point, the import_stat function is put into this protocol so that the VFS sub-system does not need to know about every VFS implementation in order to do an efficient stat for importing files. In the future it might be worth adding other functions to this protocol. --- extmod/vfs.c | 17 ++++------------- extmod/vfs.h | 5 +++++ extmod/vfs_fat.c | 9 ++++++++- extmod/vfs_fat.h | 1 - extmod/vfs_posix.c | 8 +++++++- extmod/vfs_posix.h | 3 --- 6 files changed, 24 insertions(+), 19 deletions(-) diff --git a/extmod/vfs.c b/extmod/vfs.c index 96d5019b37..77531b8742 100644 --- a/extmod/vfs.c +++ b/extmod/vfs.c @@ -34,9 +34,6 @@ #if MICROPY_VFS -#if MICROPY_VFS_POSIX -#include "extmod/vfs_posix.h" -#endif #if MICROPY_VFS_FAT #include "extmod/vfs_fat.h" #endif @@ -128,17 +125,11 @@ mp_import_stat_t mp_vfs_import_stat(const char *path) { return MP_IMPORT_STAT_NO_EXIST; } - // Fast paths for known VFS types - #if MICROPY_VFS_POSIX - if (mp_obj_get_type(vfs->obj) == &mp_type_vfs_posix) { - return mp_vfs_posix_import_stat(MP_OBJ_TO_PTR(vfs->obj), path_out); + // If the mounted object has the VFS protocol, call its import_stat helper + const mp_vfs_proto_t *proto = mp_obj_get_type(vfs->obj)->protocol; + if (proto != NULL) { + return proto->import_stat(MP_OBJ_TO_PTR(vfs->obj), path_out); } - #endif - #if MICROPY_VFS_FAT - if (mp_obj_get_type(vfs->obj) == &mp_fat_vfs_type) { - return fat_vfs_import_stat(MP_OBJ_TO_PTR(vfs->obj), path_out); - } - #endif // delegate to vfs.stat() method mp_obj_t path_o = mp_obj_new_str(path_out, strlen(path_out)); diff --git a/extmod/vfs.h b/extmod/vfs.h index f2efdbe795..730dea0431 100644 --- a/extmod/vfs.h +++ b/extmod/vfs.h @@ -45,6 +45,11 @@ #define BP_IOCTL_SEC_COUNT (4) #define BP_IOCTL_SEC_SIZE (5) +// At the moment the VFS protocol just has import_stat, but could be extended to other methods +typedef struct _mp_vfs_proto_t { + mp_import_stat_t (*import_stat)(void *self, const char *path); +} mp_vfs_proto_t; + typedef struct _mp_vfs_mount_t { const char *str; // mount point with leading / size_t len; diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 5666a6b0c1..4af836b2d0 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -47,7 +47,8 @@ #define mp_obj_fat_vfs_t fs_user_mount_t -mp_import_stat_t fat_vfs_import_stat(fs_user_mount_t *vfs, const char *path) { +STATIC mp_import_stat_t fat_vfs_import_stat(void *vfs_in, const char *path) { + fs_user_mount_t *vfs = vfs_in; FILINFO fno; assert(vfs != NULL); FRESULT res = f_stat(&vfs->fatfs, path, &fno); @@ -421,11 +422,17 @@ STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = { }; STATIC MP_DEFINE_CONST_DICT(fat_vfs_locals_dict, fat_vfs_locals_dict_table); +STATIC const mp_vfs_proto_t fat_vfs_proto = { + .import_stat = fat_vfs_import_stat, +}; + const mp_obj_type_t mp_fat_vfs_type = { { &mp_type_type }, .name = MP_QSTR_VfsFat, .make_new = fat_vfs_make_new, + .protocol = &fat_vfs_proto, .locals_dict = (mp_obj_dict_t*)&fat_vfs_locals_dict, + }; #endif // MICROPY_VFS_FAT diff --git a/extmod/vfs_fat.h b/extmod/vfs_fat.h index e0836a555b..ba2915386f 100644 --- a/extmod/vfs_fat.h +++ b/extmod/vfs_fat.h @@ -58,7 +58,6 @@ extern const mp_obj_type_t mp_fat_vfs_type; extern const mp_obj_type_t mp_type_vfs_fat_fileio; extern const mp_obj_type_t mp_type_vfs_fat_textio; -mp_import_stat_t fat_vfs_import_stat(struct _fs_user_mount_t *vfs, const char *path); MP_DECLARE_CONST_FUN_OBJ_3(fat_vfs_open_obj); #endif // MICROPY_INCLUDED_EXTMOD_VFS_FAT_H diff --git a/extmod/vfs_posix.c b/extmod/vfs_posix.c index 0db45a0c1f..6e3bb2c5bd 100644 --- a/extmod/vfs_posix.c +++ b/extmod/vfs_posix.c @@ -71,7 +71,8 @@ STATIC mp_obj_t vfs_posix_fun1_helper(mp_obj_t self_in, mp_obj_t path_in, int (* return mp_const_none; } -mp_import_stat_t mp_vfs_posix_import_stat(mp_obj_vfs_posix_t *self, const char *path) { +STATIC mp_import_stat_t mp_vfs_posix_import_stat(void *self_in, const char *path) { + mp_obj_vfs_posix_t *self = self_in; if (self->root_len != 0) { self->root.len = self->root_len; vstr_add_str(&self->root, path); @@ -347,10 +348,15 @@ STATIC const mp_rom_map_elem_t vfs_posix_locals_dict_table[] = { }; STATIC MP_DEFINE_CONST_DICT(vfs_posix_locals_dict, vfs_posix_locals_dict_table); +STATIC const mp_vfs_proto_t vfs_posix_proto = { + .import_stat = mp_vfs_posix_import_stat, +}; + const mp_obj_type_t mp_type_vfs_posix = { { &mp_type_type }, .name = MP_QSTR_VfsPosix, .make_new = vfs_posix_make_new, + .protocol = &vfs_posix_proto, .locals_dict = (mp_obj_dict_t*)&vfs_posix_locals_dict, }; diff --git a/extmod/vfs_posix.h b/extmod/vfs_posix.h index 35a255ff62..00756b4c9d 100644 --- a/extmod/vfs_posix.h +++ b/extmod/vfs_posix.h @@ -29,13 +29,10 @@ #include "py/lexer.h" #include "py/obj.h" -struct _mp_obj_vfs_posix_t; - extern const mp_obj_type_t mp_type_vfs_posix; extern const mp_obj_type_t mp_type_vfs_posix_fileio; extern const mp_obj_type_t mp_type_vfs_posix_textio; -mp_import_stat_t mp_vfs_posix_import_stat(struct _mp_obj_vfs_posix_t *self, const char *path_in); mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_obj_t mode_in); #endif // MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H From a8b9e71ac13c1cfad7bda7449683ff4b69886df0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 Jun 2018 14:31:29 +1000 Subject: [PATCH 760/828] py/mpconfig.h: Add default MICROPY_VFS_FAT config value. At least to document it's existence. --- py/mpconfig.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/py/mpconfig.h b/py/mpconfig.h index dc0fc5d40e..0ea087fb3f 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -686,6 +686,11 @@ typedef double mp_float_t; #define MICROPY_VFS_POSIX (0) #endif +// Support for VFS FAT component, to mount a FAT filesystem within VFS +#ifndef MICROPY_VFS +#define MICROPY_VFS_FAT (0) +#endif + /*****************************************************************************/ /* Fine control over Python builtins, classes, modules, etc */ From b789c640f706ff27742d81435b90d16f43da91ef Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 Jun 2018 15:07:50 +1000 Subject: [PATCH 761/828] travis: Install explicit version of urllib3 for coveralls. Coveralls requires a "recent" version of urllib3, whereas requests requires a "not so recent" version, less than 1.23. So force urllib3 v1.22 to get it all working. --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d50a5d2615..35d3e05198 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,8 +21,9 @@ before_script: - sudo apt-get install -y --force-yes gcc-arm-none-eabi # For teensy build - sudo apt-get install realpath - # For coverage testing (upgrade is used to get latest urllib3 version) - - sudo pip install --upgrade cpp-coveralls + # For coverage testing (a specific urllib3 version is needed for requests and cpp-coveralls to work together) + - sudo pip install -Iv urllib3==1.22 + - sudo pip install cpp-coveralls - gcc --version - arm-none-eabi-gcc --version - python3 --version From db5d8c97f1ee74bbd0d5b86991c6de33d0f985b6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 25 May 2018 16:48:19 +1000 Subject: [PATCH 762/828] py/obj.h: Introduce a "flags" entry in mp_obj_type_t. --- py/obj.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/py/obj.h b/py/obj.h index 8e4083920a..a64cd0f694 100644 --- a/py/obj.h +++ b/py/obj.h @@ -455,8 +455,11 @@ struct _mp_obj_type_t { // A type is an object so must start with this entry, which points to mp_type_type. mp_obj_base_t base; - // The name of this type. - qstr name; + // Flags associated with this type. + uint16_t flags; + + // The name of this type, a qstr. + uint16_t name; // Corresponds to __repr__ and __str__ special methods. mp_print_fun_t print; From bace1a16d056cc755f12f525b9f2bfb3cb4b4b50 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 25 May 2018 17:08:09 +1000 Subject: [PATCH 763/828] py/objtype: Don't expose mp_obj_instance_attr(). mp_obj_is_instance_type() can be used instead to check for instance types. --- py/objtype.c | 2 +- py/objtype.h | 3 --- py/vm.c | 4 ++-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/py/objtype.c b/py/objtype.c index 77810ce707..d7d0ed7ff8 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -764,7 +764,7 @@ STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val } } -void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { +STATIC void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (dest[0] == MP_OBJ_NULL) { mp_obj_instance_load_attr(self_in, attr, dest); } else { diff --git a/py/objtype.h b/py/objtype.h index 1f43130845..3fc8c6e1b0 100644 --- a/py/objtype.h +++ b/py/objtype.h @@ -42,9 +42,6 @@ typedef struct _mp_obj_instance_t { mp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *cls, const mp_obj_type_t **native_base); #endif -// this needs to be exposed for MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE to work -void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest); - // these need to be exposed so mp_obj_is_callable can work correctly bool mp_obj_instance_is_callable(mp_obj_t self_in); mp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args); diff --git a/py/vm.c b/py/vm.c index d24a024d54..498ecb491d 100644 --- a/py/vm.c +++ b/py/vm.c @@ -336,7 +336,7 @@ dispatch_loop: MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t top = TOP(); - if (mp_obj_get_type(top)->attr == mp_obj_instance_attr) { + if (mp_obj_is_instance_type(mp_obj_get_type(top))) { mp_obj_instance_t *self = MP_OBJ_TO_PTR(top); mp_uint_t x = *ip; mp_obj_t key = MP_OBJ_NEW_QSTR(qst); @@ -434,7 +434,7 @@ dispatch_loop: MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t top = TOP(); - if (mp_obj_get_type(top)->attr == mp_obj_instance_attr && sp[-1] != MP_OBJ_NULL) { + if (mp_obj_is_instance_type(mp_obj_get_type(top)) && sp[-1] != MP_OBJ_NULL) { mp_obj_instance_t *self = MP_OBJ_TO_PTR(top); mp_uint_t x = *ip; mp_obj_t key = MP_OBJ_NEW_QSTR(qst); From 36c105218321167d47b0fb67575a7cddc36d17e7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 25 May 2018 17:09:54 +1000 Subject: [PATCH 764/828] py/objtype: Optimise instance get/set/del by skipping special accessors. This patch is a code optimisation, trading text bytes for speed. On pyboard it's an increase of 0.06% in code size for a gain (in pystone performance) of roughly 6.5%. The patch optimises load/store/delete of attributes in user defined classes by not looking up special accessors (@property, __get__, __delete__, __set__, __setattr__ and __getattr_) if they are guaranteed not to exist in the class. Currently, if you do my_obj.foo() then the runtime has to do a few checks to see if foo is a property or has __get__, and if so delegate the call. And for stores things like my_obj.foo = 1 has to first check if foo is a property or has __set__ defined on it. Doing all those checks each and every time the attribute is accessed has a performance penalty. This patch eliminates all those checks for cases when it's guaranteed that the checks will always fail, ie no attributes are properties nor have any special accessor methods defined on them. To make this guarantee it checks all attributes of a user-defined class when it is first created. If any of the attributes of the user class are properties or have special accessors, or any of the base classes of the user class have them, then it sets a flag in the class to indicate that special accessors must be checked for. Then in the load/store/delete code it checks this flag to see if it can take the shortcut and optimise the lookup. It's an optimisation that's pretty widely applicable because it improves lookup performance for all methods of user defined classes, and stores of attributes, at least for those that don't have special accessors. And, it allows to enable descriptors with minimal additional runtime overhead if they are not used for a particular user class. There is one restriction on dynamic class creation that has been introduced by this patch: a user-defined class cannot go from zero special accessors to one special accessor (or more) after that class has been subclassed. If the script attempts this an AttributeError is raised (see addition to tests/misc/non_compliant.py for an example of this case). The cost in code space bytes for the optimisation in this patch is: unix x64: +528 unix nanbox: +508 stm32: +192 cc3200: +200 esp8266: +332 esp32: +244 Performance tests that were done: - on unix x86-64, pystone improved by about 5% - on pyboard, pystone improved by about 6.5%, from 1683 up to 1794 - on pyboard, bm_chaos (from CPython benchmark suite) improved by about 5% - on esp32, pystone improved by about 30% (but there are caching effects) - on esp32, bm_chaos improved by about 11% --- py/mpconfig.h | 8 +- py/objtype.c | 101 +++++++++++++++++++++-- tests/basics/builtin_property_inherit.py | 53 ++++++++++++ tests/misc/non_compliant.py | 10 +++ tests/misc/non_compliant.py.exp | 1 + 5 files changed, 161 insertions(+), 12 deletions(-) create mode 100644 tests/basics/builtin_property_inherit.py diff --git a/py/mpconfig.h b/py/mpconfig.h index 0ea087fb3f..26c9cd92bd 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -706,14 +706,16 @@ typedef double mp_float_t; #define MICROPY_PY_FUNCTION_ATTRS (0) #endif -// Whether to support descriptors (__get__ and __set__) -// This costs some code size and makes all load attrs and store attrs slow +// Whether to support the descriptors __get__, __set__, __delete__ +// This costs some code size and makes load/store/delete of instance +// attributes slower for the classes that use this feature #ifndef MICROPY_PY_DESCRIPTORS #define MICROPY_PY_DESCRIPTORS (0) #endif // Whether to support class __delattr__ and __setattr__ methods -// This costs some code size and makes all del attrs and store attrs slow +// This costs some code size and makes store/delete of instance +// attributes slower for the classes that use this feature #ifndef MICROPY_PY_DELATTR_SETATTR #define MICROPY_PY_DELATTR_SETATTR (0) #endif diff --git a/py/objtype.c b/py/objtype.c index d7d0ed7ff8..ef70dfce0f 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2018 Damien P. George * Copyright (c) 2014-2016 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -41,6 +41,12 @@ #define DEBUG_printf(...) (void)0 #endif +#define ENABLE_SPECIAL_ACCESSORS \ + (MICROPY_PY_DESCRIPTORS || MICROPY_PY_DELATTR_SETATTR || MICROPY_PY_BUILTINS_PROPERTY) + +#define TYPE_FLAG_IS_SUBCLASSED (0x0001) +#define TYPE_FLAG_HAS_SPECIAL_ACCESSORS (0x0002) + STATIC mp_obj_t static_class_method_make_new(const mp_obj_type_t *self_in, size_t n_args, size_t n_kw, const mp_obj_t *args); /******************************************************************************/ @@ -591,6 +597,11 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des mp_obj_class_lookup(&lookup, self->base.type); mp_obj_t member = dest[0]; if (member != MP_OBJ_NULL) { + if (!(self->base.type->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) { + // Class doesn't have any special accessors to check so return straightaway + return; + } + #if MICROPY_PY_BUILTINS_PROPERTY if (MP_OBJ_IS_TYPE(member, &mp_type_property)) { // object member is a property; delegate the load to the property @@ -652,11 +663,15 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); + if (!(self->base.type->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) { + // Class doesn't have any special accessors so skip their checks + goto skip_special_accessors; + } + #if MICROPY_PY_BUILTINS_PROPERTY || MICROPY_PY_DESCRIPTORS // With property and/or descriptors enabled we need to do a lookup // first in the class dict for the attribute to see if the store should // be delegated. - // Note: this makes all stores slow... how to fix? mp_obj_t member[2] = {MP_OBJ_NULL}; struct class_lookup_data lookup = { .obj = self, @@ -728,9 +743,9 @@ STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val } #endif + #if MICROPY_PY_DELATTR_SETATTR if (value == MP_OBJ_NULL) { // delete attribute - #if MICROPY_PY_DELATTR_SETATTR // try __delattr__ first mp_obj_t attr_delattr_method[3]; mp_load_method_maybe(self_in, MP_QSTR___delattr__, attr_delattr_method); @@ -740,13 +755,8 @@ STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val mp_call_method_n_kw(1, 0, attr_delattr_method); return true; } - #endif - - mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND); - return elem != NULL; } else { // store attribute - #if MICROPY_PY_DELATTR_SETATTR // try __setattr__ first mp_obj_t attr_setattr_method[4]; mp_load_method_maybe(self_in, MP_QSTR___setattr__, attr_setattr_method); @@ -757,8 +767,17 @@ STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val mp_call_method_n_kw(2, 0, attr_setattr_method); return true; } - #endif + } + #endif +skip_special_accessors: + + if (value == MP_OBJ_NULL) { + // delete attribute + mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND); + return elem != NULL; + } else { + // store attribute mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; return true; } @@ -899,6 +918,34 @@ STATIC mp_int_t instance_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, // - there is a constant mp_obj_type_t (called mp_type_type) for the 'type' object // - creating a new class (a new type) creates a new mp_obj_type_t +#if ENABLE_SPECIAL_ACCESSORS +STATIC bool check_for_special_accessors(mp_obj_t key, mp_obj_t value) { + #if MICROPY_PY_DELATTR_SETATTR + if (key == MP_OBJ_NEW_QSTR(MP_QSTR___setattr__) || key == MP_OBJ_NEW_QSTR(MP_QSTR___delattr__)) { + return true; + } + #endif + #if MICROPY_PY_BUILTINS_PROPERTY + if (MP_OBJ_IS_TYPE(value, &mp_type_property)) { + return true; + } + #endif + #if MICROPY_PY_DESCRIPTORS + static const uint8_t to_check[] = { + MP_QSTR___get__, MP_QSTR___set__, MP_QSTR___delete__, + }; + for (size_t i = 0; i < MP_ARRAY_SIZE(to_check); ++i) { + mp_obj_t dest_temp[2]; + mp_load_method_protected(value, to_check[i], dest_temp, true); + if (dest_temp[0] != MP_OBJ_NULL) { + return true; + } + } + #endif + return false; +} +#endif + STATIC void type_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in); @@ -985,6 +1032,19 @@ STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { dest[0] = MP_OBJ_NULL; // indicate success } } else { + #if ENABLE_SPECIAL_ACCESSORS + // Check if we add any special accessor methods with this store + if (!(self->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) { + if (check_for_special_accessors(MP_OBJ_NEW_QSTR(attr), dest[1])) { + if (self->flags & TYPE_FLAG_IS_SUBCLASSED) { + // This class is already subclassed so can't have special accessors added + mp_raise_msg(&mp_type_AttributeError, "can't add special method to already-subclassed class"); + } + self->flags |= TYPE_FLAG_HAS_SPECIAL_ACCESSORS; + } + } + #endif + // store attribute mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); elem->value = dest[1]; @@ -1016,6 +1076,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) // TODO might need to make a copy of locals_dict; at least that's how CPython does it // Basic validation of base classes + uint16_t base_flags = 0; size_t bases_len; mp_obj_t *bases_items; mp_obj_tuple_get(bases_tuple, &bases_len, &bases_items); @@ -1033,10 +1094,17 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) "type '%q' is not an acceptable base type", t->name)); } } + #if ENABLE_SPECIAL_ACCESSORS + if (mp_obj_is_instance_type(t)) { + t->flags |= TYPE_FLAG_IS_SUBCLASSED; + base_flags |= t->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS; + } + #endif } mp_obj_type_t *o = m_new0(mp_obj_type_t, 1); o->base.type = &mp_type_type; + o->flags = base_flags; o->name = name; o->print = instance_print; o->make_new = mp_obj_instance_make_new; @@ -1069,6 +1137,21 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) o->locals_dict = MP_OBJ_TO_PTR(locals_dict); + #if ENABLE_SPECIAL_ACCESSORS + // Check if the class has any special accessor methods + if (!(o->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) { + for (size_t i = 0; i < o->locals_dict->map.alloc; i++) { + if (MP_MAP_SLOT_IS_FILLED(&o->locals_dict->map, i)) { + const mp_map_elem_t *elem = &o->locals_dict->map.table[i]; + if (check_for_special_accessors(elem->key, elem->value)) { + o->flags |= TYPE_FLAG_HAS_SPECIAL_ACCESSORS; + break; + } + } + } + } + #endif + const mp_obj_type_t *native_base; size_t num_native_bases = instance_count_native_bases(o, &native_base); if (num_native_bases > 1) { diff --git a/tests/basics/builtin_property_inherit.py b/tests/basics/builtin_property_inherit.py new file mode 100644 index 0000000000..27a0913935 --- /dev/null +++ b/tests/basics/builtin_property_inherit.py @@ -0,0 +1,53 @@ +# test builtin property combined with inheritance +try: + property +except: + print("SKIP") + raise SystemExit + +# test property in a base class works for derived classes +class A: + @property + def x(self): + print('A x') + return 123 +class B(A): + pass +class C(B): + pass +class D: + pass +class E(C, D): + pass +print(A().x) +print(B().x) +print(C().x) +print(E().x) + +# test that we can add a property to base class after creation +class F: + pass +F.foo = property(lambda self: print('foo get')) +class G(F): + pass +F().foo +G().foo + +# should be able to add a property to already-subclassed class because it already has one +F.bar = property(lambda self: print('bar get')) +F().bar +G().bar + +# test case where class (H here) is already subclassed before adding attributes +class H: + pass +class I(H): + pass + +# should be able to add a normal member to already-subclassed class +H.val = 2 +print(I().val) + +# should be able to add a property to the derived class +I.baz = property(lambda self: print('baz get')) +I().baz diff --git a/tests/misc/non_compliant.py b/tests/misc/non_compliant.py index 31129f0759..580583bf39 100644 --- a/tests/misc/non_compliant.py +++ b/tests/misc/non_compliant.py @@ -139,3 +139,13 @@ class A: class B(object, A): pass B().foo() + +# can't assign property (or other special accessors) to already-subclassed class +class A: + pass +class B(A): + pass +try: + A.bar = property() +except AttributeError: + print('AttributeError') diff --git a/tests/misc/non_compliant.py.exp b/tests/misc/non_compliant.py.exp index 061e3fcc87..3f15a14406 100644 --- a/tests/misc/non_compliant.py.exp +++ b/tests/misc/non_compliant.py.exp @@ -20,3 +20,4 @@ NotImplementedError AttributeError TypeError A.foo +AttributeError From 93150a0d40a6f29907d53bba8a4a44f1c5fb2449 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 8 Jun 2018 12:23:08 +1000 Subject: [PATCH 765/828] ports: Enable descriptors on stm32, esp8266, esp32 ports. They are now efficient (in runtime performance) and provide a useful feature that's hard to obtain without them enabled. See issue #3644 and PR #3826 for background. --- ports/esp32/mpconfigport.h | 1 + ports/esp8266/mpconfigport.h | 1 + ports/stm32/mpconfigport.h | 1 + 3 files changed, 3 insertions(+) diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 24034ba16c..623f5f5161 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -57,6 +57,7 @@ // control over Python builtins #define MICROPY_PY_FUNCTION_ATTRS (1) +#define MICROPY_PY_DESCRIPTORS (1) #define MICROPY_PY_STR_BYTES_CMP_WARN (1) #define MICROPY_PY_BUILTINS_STR_UNICODE (1) #define MICROPY_PY_BUILTINS_STR_CENTER (1) diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index ff45f86aeb..8a800f017f 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -30,6 +30,7 @@ #define MICROPY_CAN_OVERRIDE_BUILTINS (1) #define MICROPY_USE_INTERNAL_ERRNO (1) #define MICROPY_ENABLE_SCHEDULER (1) +#define MICROPY_PY_DESCRIPTORS (1) #define MICROPY_PY_ALL_SPECIAL_METHODS (1) #define MICROPY_PY_BUILTINS_COMPLEX (0) #define MICROPY_PY_BUILTINS_STR_UNICODE (1) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index ecb3596fff..3093e9d8a1 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -82,6 +82,7 @@ // control over Python builtins #define MICROPY_PY_FUNCTION_ATTRS (1) +#define MICROPY_PY_DESCRIPTORS (1) #define MICROPY_PY_BUILTINS_STR_UNICODE (1) #define MICROPY_PY_BUILTINS_STR_CENTER (1) #define MICROPY_PY_BUILTINS_STR_PARTITION (1) From 190c7dba89dbb1165f682b56f278e3bc9715680c Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 8 Jun 2018 12:55:18 +1000 Subject: [PATCH 766/828] stm32/mpconfigport.h: Enable DELATTR_SETATTR and BUILTINS_NOTIMPLEMENTED MICROPY_PY_DELATTR_SETATTR can now be enabled without a performance hit for classes that don't use this feature. MICROPY_PY_BUILTINS_NOTIMPLEMENTED is a minor addition that improves compatibility with CPython. --- ports/stm32/mpconfigport.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 3093e9d8a1..89a43f3bb9 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -83,6 +83,7 @@ // control over Python builtins #define MICROPY_PY_FUNCTION_ATTRS (1) #define MICROPY_PY_DESCRIPTORS (1) +#define MICROPY_PY_DELATTR_SETATTR (1) #define MICROPY_PY_BUILTINS_STR_UNICODE (1) #define MICROPY_PY_BUILTINS_STR_CENTER (1) #define MICROPY_PY_BUILTINS_STR_PARTITION (1) @@ -94,6 +95,7 @@ #define MICROPY_PY_ALL_SPECIAL_METHODS (1) #define MICROPY_PY_BUILTINS_COMPILE (1) #define MICROPY_PY_BUILTINS_EXECFILE (1) +#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1) #define MICROPY_PY_BUILTINS_INPUT (1) #define MICROPY_PY_BUILTINS_POW3 (1) #define MICROPY_PY_BUILTINS_HELP (1) From a12d046c42dc7e786563f8247ed8aa8ac6e14a47 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 8 Jun 2018 13:00:27 +1000 Subject: [PATCH 767/828] tests/pyb: Make i2c and pyb1 pyboard tests run again. For i2c.py: the accelerometer now uses the new I2C driver so need to explicitly init the legacy i2c object to get the test working. For pyb1.py: the legacy pyb.hid() call will crash if the USB_HID object is not initialised. --- tests/pyb/i2c.py | 3 ++- tests/pyb/pyb1.py | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/pyb/i2c.py b/tests/pyb/i2c.py index a220f8e858..6875e5a5aa 100644 --- a/tests/pyb/i2c.py +++ b/tests/pyb/i2c.py @@ -19,7 +19,8 @@ i2c.deinit() accel_addr = 76 -pyb.Accel() # this will init the bus for us +pyb.Accel() # this will init the MMA for us +i2c.init(I2C.MASTER, baudrate=400000) print(i2c.scan()) print(i2c.is_ready(accel_addr)) diff --git a/tests/pyb/pyb1.py b/tests/pyb/pyb1.py index 184acbdc43..443722ca85 100644 --- a/tests/pyb/pyb1.py +++ b/tests/pyb/pyb1.py @@ -29,8 +29,6 @@ pyb.enable_irq() print(pyb.have_cdc()) -pyb.hid((0, 0, 0, 0)) # won't do anything - pyb.sync() print(len(pyb.unique_id())) From 039f196c56b97d879b7ce731cd479395dd479c3d Mon Sep 17 00:00:00 2001 From: Glenn Moloney Date: Mon, 4 Jun 2018 20:17:47 +1000 Subject: [PATCH 768/828] esp32/modnetwork: Fix isconnected() when using static IP config. Currently .isconnected() always returns True if a static IP is set, regardless of the state of the connection. This patch introduces a new flag 'wifi_sta_connected' which is set in event_handler() when GOT_IP event is received and reset when DISCONNECTED event is received (unless re-connect is successful). isconnected() now simply returns the status of this flag (for STA_IF). The pre-existing flag misleadingly named 'wifi_sta_connected" is also renamed to 'wifi_sta_connect_requested'. Fixes issue #3837 --- ports/esp32/modnetwork.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index 9f7aa77dfa..fdcb6d3cf3 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -123,6 +123,9 @@ static bool wifi_started = false; // Set to "true" if the STA interface is requested to be connected by the // user, used for automatic reassociation. +static bool wifi_sta_connect_requested = false; + +// Set to "true" if the STA interface is connected to wifi and has IP address. static bool wifi_sta_connected = false; // This function is called by the system-event task and so runs in a different @@ -132,8 +135,12 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) { case SYSTEM_EVENT_STA_START: ESP_LOGI("wifi", "STA_START"); break; + case SYSTEM_EVENT_STA_CONNECTED: + ESP_LOGI("network", "CONNECTED"); + break; case SYSTEM_EVENT_STA_GOT_IP: ESP_LOGI("network", "GOT_IP"); + wifi_sta_connected = true; break; case SYSTEM_EVENT_STA_DISCONNECTED: { // This is a workaround as ESP32 WiFi libs don't currently @@ -151,7 +158,7 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) { break; case WIFI_REASON_AUTH_FAIL: message = "\nauthentication failed"; - wifi_sta_connected = false; + wifi_sta_connect_requested = false; break; default: // Let other errors through and try to reconnect. @@ -159,7 +166,8 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) { } ESP_LOGI("wifi", "STA_DISCONNECTED, reason:%d%s", disconn->reason, message); - if (wifi_sta_connected) { + bool reconnected = false; + if (wifi_sta_connect_requested) { wifi_mode_t mode; if (esp_wifi_get_mode(&mode) == ESP_OK) { if (mode & WIFI_MODE_STA) { @@ -167,10 +175,16 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) { esp_err_t e = esp_wifi_connect(); if (e != ESP_OK) { ESP_LOGI("wifi", "error attempting to reconnect: 0x%04x", e); + } else { + reconnected = true; } } } } + if (wifi_sta_connected && !reconnected) { + // If already connected and we fail to reconnect + wifi_sta_connected = false; + } break; } default: @@ -283,7 +297,7 @@ STATIC mp_obj_t esp_connect(size_t n_args, const mp_obj_t *args) { MP_THREAD_GIL_EXIT(); ESP_EXCEPTIONS( esp_wifi_connect() ); MP_THREAD_GIL_ENTER(); - wifi_sta_connected = true; + wifi_sta_connect_requested = true; return mp_const_none; } @@ -291,7 +305,7 @@ STATIC mp_obj_t esp_connect(size_t n_args, const mp_obj_t *args) { STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_connect_obj, 1, 7, esp_connect); STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) { - wifi_sta_connected = false; + wifi_sta_connect_requested = false; ESP_EXCEPTIONS( esp_wifi_disconnect() ); return mp_const_none; } @@ -370,9 +384,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_scan_obj, esp_scan); STATIC mp_obj_t esp_isconnected(mp_obj_t self_in) { wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in); if (self->if_id == WIFI_IF_STA) { - tcpip_adapter_ip_info_t info; - tcpip_adapter_get_ip_info(WIFI_IF_STA, &info); - return mp_obj_new_bool(info.ip.addr != 0); + return mp_obj_new_bool(wifi_sta_connected); } else { wifi_sta_list_t sta; esp_wifi_ap_get_sta_list(&sta); From 24c416cc66577a2cfbe8d6f01e1386340fc042f4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 8 Jun 2018 15:29:52 +1000 Subject: [PATCH 769/828] stm32/mboot: Increase USB rx_buf and DFU buf sizes to full 2048 bytes. The DFU USB config descriptor returns 0x0800=2048 for the supported transfer size, and this applies to both TX (IN) and RX (OUT). So increase the rx_buf to support this size without having a buffer overflow on received data. With this patch mboot in USB DFU mode now works with dfu-util. --- ports/stm32/mboot/main.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c index b602f19964..a87507fd50 100644 --- a/ports/stm32/mboot/main.c +++ b/ports/stm32/mboot/main.c @@ -619,6 +619,8 @@ uint8_t i2c_slave_process_tx_byte(void) { /******************************************************************************/ // DFU +#define DFU_XFER_SIZE (2048) + enum { DFU_DNLOAD = 1, DFU_UPLOAD = 2, @@ -649,7 +651,7 @@ typedef struct _dfu_state_t { uint16_t wBlockNum; uint16_t wLength; uint32_t addr; - uint8_t buf[64] __attribute__((aligned(4))); + uint8_t buf[DFU_XFER_SIZE] __attribute__((aligned(4))); } dfu_state_t; static dfu_state_t dfu_state; @@ -762,7 +764,7 @@ static int dfu_handle_tx(int cmd, int arg, int len, uint8_t *buf, int max_len) { /******************************************************************************/ // USB -#define USB_TX_LEN (2048) +#define USB_XFER_SIZE (DFU_XFER_SIZE) enum { USB_PHY_FS_ID = 0, @@ -776,8 +778,8 @@ typedef struct _pyb_usbdd_obj_t { uint8_t bRequest; uint16_t wValue; uint16_t wLength; - uint8_t rx_buf[64]; - uint8_t tx_buf[USB_TX_LEN]; + uint8_t rx_buf[USB_XFER_SIZE]; + uint8_t tx_buf[USB_XFER_SIZE]; bool tx_pending; // RAM to hold the current descriptors, which we configure on the fly @@ -800,7 +802,7 @@ static const uint8_t dev_descr[0x12] = "\x12\x01\x00\x01\x00\x00\x00\x40\x83\x04 static uint8_t cfg_descr[9 + 9 + 9] = "\x09\x02\x1b\x00\x01\x01\x00\xc0\x32" "\x09\x04\x00\x00\x00\xfe\x01\x02\x04" - "\x09\x21\x0b\xff\x00\x00\x08\x1a\x01" // \x00\x08 goes with tx_buf[USB_TX_LEN] + "\x09\x21\x0b\xff\x00\x00\x08\x1a\x01" // \x00\x08 goes with USB_XFER_SIZE ; static uint8_t *pyb_usbdd_DeviceDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { @@ -908,7 +910,7 @@ static uint8_t pyb_usbdd_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *r } } else if (req->bmRequest == 0xa1) { // device-to-host request - int len = dfu_handle_tx(self->bRequest, self->wValue, self->wLength, self->tx_buf, USB_TX_LEN); + int len = dfu_handle_tx(self->bRequest, self->wValue, self->wLength, self->tx_buf, USB_XFER_SIZE); if (len >= 0) { self->tx_pending = true; USBD_CtlSendData(&self->hUSBDDevice, self->tx_buf, len); From 8fb95d652066b38e0dbb4fa5433de49eb601bdfe Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 8 Jun 2018 15:32:49 +1000 Subject: [PATCH 770/828] tools/pydfu.py: Increase download packet size to full 2048 bytes. The ST DFU bootloader supports a transfer size up to 2048 bytes, so send that much data on each download (to device) packet. This almost halves total download time. --- tools/pydfu.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/pydfu.py b/tools/pydfu.py index 3f11de0679..a33e497129 100755 --- a/tools/pydfu.py +++ b/tools/pydfu.py @@ -168,7 +168,7 @@ def write_memory(addr, buf, progress=None, progress_addr=0, progress_size=0): print ("Addr 0x%x %dKBs/%dKBs..." % (xfer_base + xfer_bytes, xfer_bytes // 1024, xfer_total // 1024)) - if progress and xfer_count % 256 == 0: + if progress and xfer_count % 2 == 0: progress(progress_addr, xfer_base + xfer_bytes - progress_addr, progress_size) @@ -176,7 +176,9 @@ def write_memory(addr, buf, progress=None, progress_addr=0, progress_size=0): set_address(xfer_base+xfer_bytes) # Send DNLOAD with fw data - chunk = min(64, xfer_total-xfer_bytes) + # the "2048" is the DFU transfer size supported by the ST DFU bootloader + # TODO: this number should be extracted from the USB config descriptor + chunk = min(2048, xfer_total-xfer_bytes) __dev.ctrl_transfer(0x21, __DFU_DNLOAD, 2, __DFU_INTERFACE, buf[xfer_bytes:xfer_bytes + chunk], __TIMEOUT) From 522ea80f06a80fd799bd57de351373ceaeeae325 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 31 May 2018 23:10:48 +1000 Subject: [PATCH 771/828] py/gc: Add gc_sweep_all() function to run all remaining finalisers. This patch adds the gc_sweep_all() function which does a garbage collection without tracing any root pointers, so frees all the memory, and most importantly runs any remaining finalisers. This helps primarily for soft reset: it will close any open files, any open sockets, and help to get the system back to a clean state upon soft reset. --- py/gc.c | 7 +++++++ py/gc.h | 3 +++ 2 files changed, 10 insertions(+) diff --git a/py/gc.c b/py/gc.c index e92b81ece7..0fc43ef495 100644 --- a/py/gc.c +++ b/py/gc.c @@ -362,6 +362,13 @@ void gc_collect_end(void) { GC_EXIT(); } +void gc_sweep_all(void) { + GC_ENTER(); + MP_STATE_MEM(gc_lock_depth)++; + MP_STATE_MEM(gc_stack_overflow) = 0; + gc_collect_end(); +} + void gc_info(gc_info_t *info) { GC_ENTER(); info->total = MP_STATE_MEM(gc_pool_end) - MP_STATE_MEM(gc_pool_start); diff --git a/py/gc.h b/py/gc.h index 739349c1f5..73d86e6c31 100644 --- a/py/gc.h +++ b/py/gc.h @@ -45,6 +45,9 @@ void gc_collect_start(void); void gc_collect_root(void **ptrs, size_t len); void gc_collect_end(void); +// Use this function to sweep the whole heap and run all finalisers +void gc_sweep_all(void); + void *gc_alloc(size_t n_bytes, bool has_finaliser); void gc_free(void *ptr); // does not call finaliser size_t gc_nbytes(const void *ptr); From b2fa1b50edaea43007d692d24391c6f3aa4d15ca Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 31 May 2018 23:11:08 +1000 Subject: [PATCH 772/828] ports: Call gc_sweep_all() when doing a soft reset. This calls finalisers of things like files and sockets to cleanly close them. --- ports/esp32/main.c | 2 ++ ports/esp8266/main.c | 1 + ports/stm32/main.c | 2 ++ ports/unix/main.c | 4 ++++ 4 files changed, 9 insertions(+) diff --git a/ports/esp32/main.c b/ports/esp32/main.c index e7290c7eb8..acbbfdccce 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -116,6 +116,8 @@ soft_reset: mp_thread_deinit(); #endif + gc_sweep_all(); + mp_hal_stdout_tx_str("PYB: soft reboot\r\n"); // deinitialise peripherals diff --git a/ports/esp8266/main.c b/ports/esp8266/main.c index 975262fd16..7e5034b04a 100644 --- a/ports/esp8266/main.c +++ b/ports/esp8266/main.c @@ -88,6 +88,7 @@ STATIC void mp_reset(void) { } void soft_reset(void) { + gc_sweep_all(); mp_hal_stdout_tx_str("PYB: soft reboot\r\n"); mp_hal_delay_us(10000); // allow UART to flush output mp_reset(); diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 19c77453f9..c018d2de2a 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -756,5 +756,7 @@ soft_reset_exit: pyb_thread_deinit(); #endif + gc_sweep_all(); + goto soft_reset; } diff --git a/ports/unix/main.c b/ports/unix/main.c index b68fe92797..1cf237a2b2 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -647,6 +647,10 @@ MP_NOINLINE int main_(int argc, char **argv) { } #endif + #if defined(MICROPY_UNIX_COVERAGE) + gc_sweep_all(); + #endif + mp_deinit(); #if MICROPY_ENABLE_GC && !defined(NDEBUG) From 6a445b60fad87c94a1d00ce3a043b881a1f7a5a4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 2 Jun 2018 00:21:46 +1000 Subject: [PATCH 773/828] py/lexer: Add support for underscores in numeric literals. This is a very convenient feature introduced in Python 3.6 by PEP 515. --- py/lexer.c | 2 ++ py/parsenum.c | 4 ++++ tests/basics/python36.py | 10 ++++++++++ tests/basics/python36.py.exp | 5 +++++ tests/float/python36.py | 10 ++++++++++ tests/float/python36.py.exp | 5 +++++ 6 files changed, 36 insertions(+) create mode 100644 tests/basics/python36.py create mode 100644 tests/basics/python36.py.exp create mode 100644 tests/float/python36.py create mode 100644 tests/float/python36.py.exp diff --git a/py/lexer.c b/py/lexer.c index 6017d69d6d..e161700b16 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -590,6 +590,8 @@ void mp_lexer_to_next(mp_lexer_t *lex) { } vstr_add_char(&lex->vstr, CUR_CHAR(lex)); next_char(lex); + } else if (is_char(lex, '_')) { + next_char(lex); } else { break; } diff --git a/py/parsenum.c b/py/parsenum.c index 354d0f756c..b7e5a3c833 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -83,6 +83,8 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m mp_uint_t dig = *str; if ('0' <= dig && dig <= '9') { dig -= '0'; + } else if (dig == '_') { + continue; } else { dig |= 0x20; // make digit lower-case if ('a' <= dig && dig <= 'z') { @@ -273,6 +275,8 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool } else if (allow_imag && (dig | 0x20) == 'j') { imag = true; break; + } else if (dig == '_') { + continue; } else { // unknown character str--; diff --git a/tests/basics/python36.py b/tests/basics/python36.py new file mode 100644 index 0000000000..20ecd9227d --- /dev/null +++ b/tests/basics/python36.py @@ -0,0 +1,10 @@ +# tests for things that only Python 3.6 supports + +# underscores in numeric literals +print(100_000) +print(0b1010_0101) +print(0xff_ff) + +# underscore supported by int constructor +print(int('1_2_3')) +print(int('0o1_2_3', 8)) diff --git a/tests/basics/python36.py.exp b/tests/basics/python36.py.exp new file mode 100644 index 0000000000..4b65daafa1 --- /dev/null +++ b/tests/basics/python36.py.exp @@ -0,0 +1,5 @@ +100000 +165 +65535 +123 +83 diff --git a/tests/float/python36.py b/tests/float/python36.py new file mode 100644 index 0000000000..6e8fb1f213 --- /dev/null +++ b/tests/float/python36.py @@ -0,0 +1,10 @@ +# tests for things that only Python 3.6 supports, needing floats + +# underscores in numeric literals +print(1_000.1_8) +print('%.2g' % 1e1_2) + +# underscore supported by int/float constructors +print(float('1_2_3')) +print(float('1_2_3.4')) +print('%.2g' % float('1e1_3')) diff --git a/tests/float/python36.py.exp b/tests/float/python36.py.exp new file mode 100644 index 0000000000..3febfed9a0 --- /dev/null +++ b/tests/float/python36.py.exp @@ -0,0 +1,5 @@ +1000.18 +1e+12 +123.0 +123.4 +1e+13 From af0932a7793478f0b90b754d38955d69700b0bee Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 4 Jun 2018 15:54:26 +1000 Subject: [PATCH 774/828] py/modio: Add uio.IOBase class to allow to define user streams. A user class derived from IOBase and implementing readinto/write/ioctl can now be used anywhere a native stream object is accepted. The mapping from C to Python is: stream_p->read --> readinto(buf) stream_p->write --> write(buf) stream_p->ioctl --> ioctl(request, arg) Among other things it allows the user to: - create an object which can be passed as the file argument to print: print(..., file=myobj), and then print will pass all the data to the object via the objects write method (same as CPython) - pass a user object to uio.BufferedWriter to buffer the writes (same as CPython) - use select.select on a user object - register user objects with select.poll, in particular so user objects can be used with uasyncio - create user files that can be returned from user filesystems, and import can import scripts from these user files For example: class MyOut(io.IOBase): def write(self, buf): print('write', repr(buf)) return len(buf) print('hello', file=MyOut()) The feature is enabled via MICROPY_PY_IO_IOBASE which is disabled by default. --- py/modio.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++ py/mpconfig.h | 5 ++++ 2 files changed, 74 insertions(+) diff --git a/py/modio.c b/py/modio.c index 3a5c69c4c1..e75432b28d 100644 --- a/py/modio.c +++ b/py/modio.c @@ -30,6 +30,8 @@ #include "py/runtime.h" #include "py/builtin.h" #include "py/stream.h" +#include "py/binary.h" +#include "py/objarray.h" #include "py/objstringio.h" #include "py/frozenmod.h" @@ -38,6 +40,70 @@ extern const mp_obj_type_t mp_type_fileio; extern const mp_obj_type_t mp_type_textio; +#if MICROPY_PY_IO_IOBASE + +STATIC const mp_obj_type_t mp_type_iobase; + +STATIC mp_obj_base_t iobase_singleton = {&mp_type_iobase}; + +STATIC mp_obj_t iobase_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)type; + (void)n_args; + (void)n_kw; + (void)args; + return MP_OBJ_FROM_PTR(&iobase_singleton); +} + +STATIC mp_uint_t iobase_read_write(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode, qstr qst) { + mp_obj_t dest[3]; + mp_load_method(obj, qst, dest); + mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, size, buf}; + dest[2] = MP_OBJ_FROM_PTR(&ar); + mp_obj_t ret = mp_call_method_n_kw(1, 0, dest); + if (ret == mp_const_none) { + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } else { + return mp_obj_get_int(ret); + } +} +STATIC mp_uint_t iobase_read(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode) { + return iobase_read_write(obj, buf, size, errcode, MP_QSTR_readinto); +} + +STATIC mp_uint_t iobase_write(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode) { + return iobase_read_write(obj, (void*)buf, size, errcode, MP_QSTR_write); +} + +STATIC mp_uint_t iobase_ioctl(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_t dest[4]; + mp_load_method(obj, MP_QSTR_ioctl, dest); + dest[2] = mp_obj_new_int_from_uint(request); + dest[3] = mp_obj_new_int_from_uint(arg); + mp_int_t ret = mp_obj_get_int(mp_call_method_n_kw(2, 0, dest)); + if (ret >= 0) { + return ret; + } else { + *errcode = -ret; + return MP_STREAM_ERROR; + } +} + +STATIC const mp_stream_p_t iobase_p = { + .read = iobase_read, + .write = iobase_write, + .ioctl = iobase_ioctl, +}; + +STATIC const mp_obj_type_t mp_type_iobase = { + { &mp_type_type }, + .name = MP_QSTR_IOBase, + .make_new = iobase_make_new, + .protocol = &iobase_p, +}; + +#endif // MICROPY_PY_IO_IOBASE + #if MICROPY_PY_IO_BUFFEREDWRITER typedef struct _mp_obj_bufwriter_t { mp_obj_base_t base; @@ -187,6 +253,9 @@ STATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = { // Note: mp_builtin_open_obj should be defined by port, it's not // part of the core. { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, + #if MICROPY_PY_IO_IOBASE + { MP_ROM_QSTR(MP_QSTR_IOBase), MP_ROM_PTR(&mp_type_iobase) }, + #endif #if MICROPY_PY_IO_RESOURCE_STREAM { MP_ROM_QSTR(MP_QSTR_resource_stream), MP_ROM_PTR(&resource_stream_obj) }, #endif diff --git a/py/mpconfig.h b/py/mpconfig.h index 26c9cd92bd..a85b22128e 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -998,6 +998,11 @@ typedef double mp_float_t; #define MICROPY_PY_IO (1) #endif +// Whether to provide "io.IOBase" class to support user streams +#ifndef MICROPY_PY_IO_IOBASE +#define MICROPY_PY_IO_IOBASE (0) +#endif + // Whether to provide "uio.resource_stream()" function with // the semantics of CPython's pkg_resources.resource_stream() // (allows to access binary resources in frozen source packages). From 565f590586e89d837db3add08b8c926560f88f8b Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 4 Jun 2018 16:04:28 +1000 Subject: [PATCH 775/828] ports: Enable IOBase on unix, stm32, esp8266 and esp32. It's a core feature, in particular required for user-streams with uasyncio. --- ports/esp32/mpconfigport.h | 1 + ports/esp8266/mpconfigport.h | 1 + ports/stm32/mpconfigport.h | 1 + ports/unix/mpconfigport.h | 1 + 4 files changed, 4 insertions(+) diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 623f5f5161..3c49eb24ed 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -99,6 +99,7 @@ #define MICROPY_PY_CMATH (1) #define MICROPY_PY_GC (1) #define MICROPY_PY_IO (1) +#define MICROPY_PY_IO_IOBASE (1) #define MICROPY_PY_IO_FILEIO (1) #define MICROPY_PY_IO_BYTESIO (1) #define MICROPY_PY_IO_BUFFEREDWRITER (1) diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index 8a800f017f..97b3090867 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -56,6 +56,7 @@ #define MICROPY_PY_MATH (1) #define MICROPY_PY_CMATH (0) #define MICROPY_PY_IO (1) +#define MICROPY_PY_IO_IOBASE (1) #define MICROPY_PY_IO_FILEIO (1) #define MICROPY_PY_STRUCT (1) #define MICROPY_PY_SYS (1) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 89a43f3bb9..a038664e83 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -108,6 +108,7 @@ #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) #define MICROPY_PY_CMATH (1) #define MICROPY_PY_IO (1) +#define MICROPY_PY_IO_IOBASE (1) #define MICROPY_PY_IO_FILEIO (MICROPY_VFS_FAT) // because mp_type_fileio/textio point to fatfs impl #define MICROPY_PY_SYS_MAXSIZE (1) #define MICROPY_PY_SYS_EXIT (1) diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index 016dabf9f4..e0f9d99957 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -104,6 +104,7 @@ #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) #endif #define MICROPY_PY_CMATH (1) +#define MICROPY_PY_IO_IOBASE (1) #define MICROPY_PY_IO_FILEIO (1) #define MICROPY_PY_GC_COLLECT_RETVAL (1) #define MICROPY_MODULE_FROZEN_STR (1) From 9144b1f10c5f48a93fdb2aefa528813bd60a2f85 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 4 Jun 2018 16:24:15 +1000 Subject: [PATCH 776/828] tests/io: Add simple IOBase test. --- tests/io/iobase.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/io/iobase.py diff --git a/tests/io/iobase.py b/tests/io/iobase.py new file mode 100644 index 0000000000..6f554b00f0 --- /dev/null +++ b/tests/io/iobase.py @@ -0,0 +1,19 @@ +try: + import uio as io +except: + import io + +try: + io.IOBase +except AttributeError: + print('SKIP') + raise SystemExit + + +class MyIO(io.IOBase): + def write(self, buf): + # CPython and uPy pass in different types for buf (str vs bytearray) + print('write', len(buf)) + return len(buf) + +print('test', file=MyIO()) From c901cc6862e982b733a45412b649d7f404751b42 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 4 Jun 2018 16:25:06 +1000 Subject: [PATCH 777/828] tests/extmod: Add test for VFS and user-defined filesystem and files. --- tests/extmod/vfs_userfs.py | 68 ++++++++++++++++++++++++++++++++++ tests/extmod/vfs_userfs.py.exp | 12 ++++++ tests/run-tests | 1 + 3 files changed, 81 insertions(+) create mode 100644 tests/extmod/vfs_userfs.py create mode 100644 tests/extmod/vfs_userfs.py.exp diff --git a/tests/extmod/vfs_userfs.py b/tests/extmod/vfs_userfs.py new file mode 100644 index 0000000000..e913f9748c --- /dev/null +++ b/tests/extmod/vfs_userfs.py @@ -0,0 +1,68 @@ +# test VFS functionality with a user-defined filesystem +# also tests parts of uio.IOBase implementation + +import sys, uio + +try: + uio.IOBase + import uos + uos.mount +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + + +class UserFile(uio.IOBase): + def __init__(self, data): + self.data = data + self.pos = 0 + def read(self): + return self.data + def readinto(self, buf): + n = 0 + while n < len(buf) and self.pos < len(self.data): + buf[n] = self.data[self.pos] + n += 1 + self.pos += 1 + return n + def ioctl(self, req, arg): + print('ioctl', req, arg) + return 0 + + +class UserFS: + def __init__(self, files): + self.files = files + def mount(self, readonly, mksfs): + pass + def umount(self): + pass + def stat(self, path): + print('stat', path) + if path in self.files: + return (32768, 0, 0, 0, 0, 0, 0, 0, 0, 0) + raise OSError + def open(self, path, mode): + print('open', path, mode) + return UserFile(self.files[path]) + + +# create and mount a user filesystem +user_files = { + '/data.txt': b"some data in a text file\n", + '/usermod1.py': b"print('in usermod1')\nimport usermod2", + '/usermod2.py': b"print('in usermod2')", +} +uos.mount(UserFS(user_files), '/userfs') + +# open and read a file +f = open('/userfs/data.txt') +print(f.read()) + +# import files from the user filesystem +sys.path.append('/userfs') +import usermod1 + +# unmount and undo path addition +uos.umount('/userfs') +sys.path.pop() diff --git a/tests/extmod/vfs_userfs.py.exp b/tests/extmod/vfs_userfs.py.exp new file mode 100644 index 0000000000..6a4d925b91 --- /dev/null +++ b/tests/extmod/vfs_userfs.py.exp @@ -0,0 +1,12 @@ +open /data.txt r +b'some data in a text file\n' +stat /usermod1 +stat /usermod1.py +open /usermod1.py r +ioctl 4 0 +in usermod1 +stat /usermod2 +stat /usermod2.py +open /usermod2.py r +ioctl 4 0 +in usermod2 diff --git a/tests/run-tests b/tests/run-tests index 25fb33a3fd..cfd7c40379 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -364,6 +364,7 @@ def run_tests(pyb, tests, args, base_path="."): skip_tests.add('micropython/schedule.py') # native code doesn't check pending events skip_tests.add('stress/gc_trace.py') # requires yield skip_tests.add('stress/recursive_gen.py') # requires yield + skip_tests.add('extmod/vfs_userfs.py') # because native doesn't properly handle globals across different modules for test_file in tests: test_file = test_file.replace('\\', '/') From b045ebd354b2e1cdb268ec5667d08db15dab747e Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Sat, 9 Jun 2018 02:38:34 +0300 Subject: [PATCH 778/828] extmod/moduhashlib: Prefix all Python methods and objects with uhashlib. For consistency with other modules, and to help avoid clashes with the actual underlying functions that do the hashing (eg crypto-algorithms/sha256.c:sha256_update). --- extmod/moduhashlib.c | 74 ++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/extmod/moduhashlib.c b/extmod/moduhashlib.c index 6469dcfa30..ba26e56e57 100644 --- a/extmod/moduhashlib.c +++ b/extmod/moduhashlib.c @@ -50,44 +50,44 @@ typedef struct _mp_obj_hash_t { char state[0]; } mp_obj_hash_t; -STATIC mp_obj_t hash_update(mp_obj_t self_in, mp_obj_t arg); +STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg); -STATIC mp_obj_t hash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { +STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 0, 1, false); mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(CRYAL_SHA256_CTX)); o->base.type = type; sha256_init((CRYAL_SHA256_CTX*)o->state); if (n_args == 1) { - hash_update(MP_OBJ_FROM_PTR(o), args[0]); + uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]); } return MP_OBJ_FROM_PTR(o); } #if MICROPY_PY_UHASHLIB_SHA1 -STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg); +STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg); #if MICROPY_SSL_AXTLS -STATIC mp_obj_t sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { +STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 0, 1, false); mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(SHA1_CTX)); o->base.type = type; SHA1_Init((SHA1_CTX*)o->state); if (n_args == 1) { - sha1_update(MP_OBJ_FROM_PTR(o), args[0]); + uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]); } return MP_OBJ_FROM_PTR(o); } #endif #if MICROPY_SSL_MBEDTLS -STATIC mp_obj_t sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { +STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 0, 1, false); mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha1_context)); o->base.type = type; mbedtls_sha1_init((mbedtls_sha1_context*)o->state); mbedtls_sha1_starts((mbedtls_sha1_context*)o->state); if (n_args == 1) { - sha1_update(MP_OBJ_FROM_PTR(o), args[0]); + uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]); } return MP_OBJ_FROM_PTR(o); } @@ -95,19 +95,19 @@ STATIC mp_obj_t sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n #endif -STATIC mp_obj_t hash_update(mp_obj_t self_in, mp_obj_t arg) { +STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) { mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_buffer_info_t bufinfo; mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); sha256_update((CRYAL_SHA256_CTX*)self->state, bufinfo.buf, bufinfo.len); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_2(hash_update_obj, hash_update); +MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha256_update_obj, uhashlib_sha256_update); #if MICROPY_PY_UHASHLIB_SHA1 #if MICROPY_SSL_AXTLS -STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg) { +STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) { mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_buffer_info_t bufinfo; mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); @@ -117,7 +117,7 @@ STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg) { #endif #if MICROPY_SSL_MBEDTLS -STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg) { +STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) { mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_buffer_info_t bufinfo; mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); @@ -126,22 +126,22 @@ STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg) { } #endif -MP_DEFINE_CONST_FUN_OBJ_2(sha1_update_obj, sha1_update); +MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha1_update_obj, uhashlib_sha1_update); #endif -STATIC mp_obj_t hash_digest(mp_obj_t self_in) { +STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) { mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); vstr_t vstr; vstr_init_len(&vstr, SHA256_BLOCK_SIZE); sha256_final((CRYAL_SHA256_CTX*)self->state, (byte*)vstr.buf); return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } -MP_DEFINE_CONST_FUN_OBJ_1(hash_digest_obj, hash_digest); +MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha256_digest_obj, uhashlib_sha256_digest); #if MICROPY_PY_UHASHLIB_SHA1 #if MICROPY_SSL_AXTLS -STATIC mp_obj_t sha1_digest(mp_obj_t self_in) { +STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) { mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); vstr_t vstr; vstr_init_len(&vstr, SHA1_SIZE); @@ -151,7 +151,7 @@ STATIC mp_obj_t sha1_digest(mp_obj_t self_in) { #endif #if MICROPY_SSL_MBEDTLS -STATIC mp_obj_t sha1_digest(mp_obj_t self_in) { +STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) { mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); vstr_t vstr; vstr_init_len(&vstr, 20); @@ -161,51 +161,51 @@ STATIC mp_obj_t sha1_digest(mp_obj_t self_in) { } #endif -MP_DEFINE_CONST_FUN_OBJ_1(sha1_digest_obj, sha1_digest); +MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha1_digest_obj, uhashlib_sha1_digest); #endif -STATIC const mp_rom_map_elem_t hash_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&hash_update_obj) }, - { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&hash_digest_obj) }, +STATIC const mp_rom_map_elem_t uhashlib_sha256_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_sha256_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_sha256_digest_obj) }, }; -STATIC MP_DEFINE_CONST_DICT(hash_locals_dict, hash_locals_dict_table); +STATIC MP_DEFINE_CONST_DICT(uhashlib_sha256_locals_dict, uhashlib_sha256_locals_dict_table); -STATIC const mp_obj_type_t sha256_type = { +STATIC const mp_obj_type_t uhashlib_sha256_type = { { &mp_type_type }, .name = MP_QSTR_sha256, - .make_new = hash_make_new, - .locals_dict = (void*)&hash_locals_dict, + .make_new = uhashlib_sha256_make_new, + .locals_dict = (void*)&uhashlib_sha256_locals_dict, }; #if MICROPY_PY_UHASHLIB_SHA1 -STATIC const mp_rom_map_elem_t sha1_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&sha1_update_obj) }, - { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&sha1_digest_obj) }, +STATIC const mp_rom_map_elem_t uhashlib_sha1_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_sha1_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_sha1_digest_obj) }, }; -STATIC MP_DEFINE_CONST_DICT(sha1_locals_dict, sha1_locals_dict_table); +STATIC MP_DEFINE_CONST_DICT(uhashlib_sha1_locals_dict, uhashlib_sha1_locals_dict_table); -STATIC const mp_obj_type_t sha1_type = { +STATIC const mp_obj_type_t uhashlib_sha1_type = { { &mp_type_type }, .name = MP_QSTR_sha1, - .make_new = sha1_make_new, - .locals_dict = (void*)&sha1_locals_dict, + .make_new = uhashlib_sha1_make_new, + .locals_dict = (void*)&uhashlib_sha1_locals_dict, }; #endif -STATIC const mp_rom_map_elem_t mp_module_hashlib_globals_table[] = { +STATIC const mp_rom_map_elem_t mp_module_uhashlib_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uhashlib) }, - { MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&sha256_type) }, + { MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&uhashlib_sha256_type) }, #if MICROPY_PY_UHASHLIB_SHA1 - { MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&sha1_type) }, + { MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&uhashlib_sha1_type) }, #endif }; -STATIC MP_DEFINE_CONST_DICT(mp_module_hashlib_globals, mp_module_hashlib_globals_table); +STATIC MP_DEFINE_CONST_DICT(mp_module_uhashlib_globals, mp_module_uhashlib_globals_table); const mp_obj_module_t mp_module_uhashlib = { .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&mp_module_hashlib_globals, + .globals = (mp_obj_dict_t*)&mp_module_uhashlib_globals, }; #include "crypto-algorithms/sha256.c" From 38682d4629c0c87d3a20330dcb10cb4e01e09aed Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Sat, 9 Jun 2018 02:46:08 +0300 Subject: [PATCH 779/828] extmod/moduhashlib: Reorder funcs so that they are grouped by hash type. Makes the code much more readable by reducing the number of #ifdefs and keeping related functions close. --- extmod/moduhashlib.c | 148 +++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 83 deletions(-) diff --git a/extmod/moduhashlib.c b/extmod/moduhashlib.c index ba26e56e57..2eb90ed739 100644 --- a/extmod/moduhashlib.c +++ b/extmod/moduhashlib.c @@ -63,38 +63,6 @@ STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_arg return MP_OBJ_FROM_PTR(o); } -#if MICROPY_PY_UHASHLIB_SHA1 -STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg); - -#if MICROPY_SSL_AXTLS -STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 0, 1, false); - mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(SHA1_CTX)); - o->base.type = type; - SHA1_Init((SHA1_CTX*)o->state); - if (n_args == 1) { - uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]); - } - return MP_OBJ_FROM_PTR(o); -} -#endif - -#if MICROPY_SSL_MBEDTLS -STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 0, 1, false); - mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha1_context)); - o->base.type = type; - mbedtls_sha1_init((mbedtls_sha1_context*)o->state); - mbedtls_sha1_starts((mbedtls_sha1_context*)o->state); - if (n_args == 1) { - uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]); - } - return MP_OBJ_FROM_PTR(o); -} -#endif - -#endif - STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) { mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_buffer_info_t bufinfo; @@ -104,31 +72,6 @@ STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) { } MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha256_update_obj, uhashlib_sha256_update); -#if MICROPY_PY_UHASHLIB_SHA1 - -#if MICROPY_SSL_AXTLS -STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) { - mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); - SHA1_Update((SHA1_CTX*)self->state, bufinfo.buf, bufinfo.len); - return mp_const_none; -} -#endif - -#if MICROPY_SSL_MBEDTLS -STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) { - mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); - mbedtls_sha1_update((mbedtls_sha1_context*)self->state, bufinfo.buf, bufinfo.len); - return mp_const_none; -} -#endif - -MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha1_update_obj, uhashlib_sha1_update); -#endif - STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) { mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); vstr_t vstr; @@ -138,32 +81,6 @@ STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha256_digest_obj, uhashlib_sha256_digest); -#if MICROPY_PY_UHASHLIB_SHA1 - -#if MICROPY_SSL_AXTLS -STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) { - mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); - vstr_t vstr; - vstr_init_len(&vstr, SHA1_SIZE); - SHA1_Final((byte*)vstr.buf, (SHA1_CTX*)self->state); - return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); -} -#endif - -#if MICROPY_SSL_MBEDTLS -STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) { - mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); - vstr_t vstr; - vstr_init_len(&vstr, 20); - mbedtls_sha1_finish((mbedtls_sha1_context*)self->state, (byte*)vstr.buf); - mbedtls_sha1_free((mbedtls_sha1_context*)self->state); - return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); -} -#endif - -MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha1_digest_obj, uhashlib_sha1_digest); -#endif - STATIC const mp_rom_map_elem_t uhashlib_sha256_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_sha256_update_obj) }, { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_sha256_digest_obj) }, @@ -179,6 +96,71 @@ STATIC const mp_obj_type_t uhashlib_sha256_type = { }; #if MICROPY_PY_UHASHLIB_SHA1 +STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg); + +#if MICROPY_SSL_AXTLS +STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(SHA1_CTX)); + o->base.type = type; + SHA1_Init((SHA1_CTX*)o->state); + if (n_args == 1) { + uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]); + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); + SHA1_Update((SHA1_CTX*)self->state, bufinfo.buf, bufinfo.len); + return mp_const_none; +} + +STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + vstr_t vstr; + vstr_init_len(&vstr, SHA1_SIZE); + SHA1_Final((byte*)vstr.buf, (SHA1_CTX*)self->state); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +#endif + +#if MICROPY_SSL_MBEDTLS +STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha1_context)); + o->base.type = type; + mbedtls_sha1_init((mbedtls_sha1_context*)o->state); + mbedtls_sha1_starts((mbedtls_sha1_context*)o->state); + if (n_args == 1) { + uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]); + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); + mbedtls_sha1_update((mbedtls_sha1_context*)self->state, bufinfo.buf, bufinfo.len); + return mp_const_none; +} + +STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + vstr_t vstr; + vstr_init_len(&vstr, 20); + mbedtls_sha1_finish((mbedtls_sha1_context*)self->state, (byte*)vstr.buf); + mbedtls_sha1_free((mbedtls_sha1_context*)self->state); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +#endif + +MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha1_update_obj, uhashlib_sha1_update); +MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha1_digest_obj, uhashlib_sha1_digest); + STATIC const mp_rom_map_elem_t uhashlib_sha1_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_sha1_update_obj) }, { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_sha1_digest_obj) }, From 6630354ffe9f33d2af8154fbac003cb4db0cc348 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Sat, 9 Jun 2018 02:48:29 +0300 Subject: [PATCH 780/828] extmod/moduhashlib: Allow to disable the sha256 class. Via the config value MICROPY_PY_UHASHLIB_SHA256. Default to enabled to keep backwards compatibility. Also add default value for the sha1 class, to at least document its existence. --- extmod/moduhashlib.c | 8 ++++++++ py/mpconfig.h | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/extmod/moduhashlib.c b/extmod/moduhashlib.c index 2eb90ed739..e47bae0a02 100644 --- a/extmod/moduhashlib.c +++ b/extmod/moduhashlib.c @@ -31,7 +31,9 @@ #if MICROPY_PY_UHASHLIB +#if MICROPY_PY_UHASHLIB_SHA256 #include "crypto-algorithms/sha256.h" +#endif #if MICROPY_PY_UHASHLIB_SHA1 @@ -50,6 +52,7 @@ typedef struct _mp_obj_hash_t { char state[0]; } mp_obj_hash_t; +#if MICROPY_PY_UHASHLIB_SHA256 STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg); STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { @@ -94,6 +97,7 @@ STATIC const mp_obj_type_t uhashlib_sha256_type = { .make_new = uhashlib_sha256_make_new, .locals_dict = (void*)&uhashlib_sha256_locals_dict, }; +#endif #if MICROPY_PY_UHASHLIB_SHA1 STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg); @@ -177,7 +181,9 @@ STATIC const mp_obj_type_t uhashlib_sha1_type = { STATIC const mp_rom_map_elem_t mp_module_uhashlib_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uhashlib) }, + #if MICROPY_PY_UHASHLIB_SHA256 { MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&uhashlib_sha256_type) }, + #endif #if MICROPY_PY_UHASHLIB_SHA1 { MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&uhashlib_sha1_type) }, #endif @@ -190,6 +196,8 @@ const mp_obj_module_t mp_module_uhashlib = { .globals = (mp_obj_dict_t*)&mp_module_uhashlib_globals, }; +#if MICROPY_PY_UHASHLIB_SHA256 #include "crypto-algorithms/sha256.c" +#endif #endif //MICROPY_PY_UHASHLIB diff --git a/py/mpconfig.h b/py/mpconfig.h index a85b22128e..08d1005491 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1155,6 +1155,14 @@ typedef double mp_float_t; #define MICROPY_PY_UHASHLIB (0) #endif +#ifndef MICROPY_PY_UHASHLIB_SHA1 +#define MICROPY_PY_UHASHLIB_SHA1 (0) +#endif + +#ifndef MICROPY_PY_UHASHLIB_SHA256 +#define MICROPY_PY_UHASHLIB_SHA256 (1) +#endif + #ifndef MICROPY_PY_UBINASCII #define MICROPY_PY_UBINASCII (0) #endif From 6963ee90750f0af94cad1a823cf89aec97e0242d Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Sat, 9 Jun 2018 03:00:21 +0300 Subject: [PATCH 781/828] extmod/moduhashlib: Allow using the sha256 implementation of mbedTLS. --- extmod/moduhashlib.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/extmod/moduhashlib.c b/extmod/moduhashlib.c index e47bae0a02..446aa48271 100644 --- a/extmod/moduhashlib.c +++ b/extmod/moduhashlib.c @@ -32,9 +32,15 @@ #if MICROPY_PY_UHASHLIB #if MICROPY_PY_UHASHLIB_SHA256 + +#if MICROPY_SSL_MBEDTLS +#include "mbedtls/sha256.h" +#else #include "crypto-algorithms/sha256.h" #endif +#endif + #if MICROPY_PY_UHASHLIB_SHA1 #if MICROPY_SSL_AXTLS @@ -55,6 +61,38 @@ typedef struct _mp_obj_hash_t { #if MICROPY_PY_UHASHLIB_SHA256 STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg); +#if MICROPY_SSL_MBEDTLS + +STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha256_context)); + o->base.type = type; + mbedtls_sha256_init((mbedtls_sha256_context*)&o->state); + mbedtls_sha256_starts((mbedtls_sha256_context*)&o->state, 0); + if (n_args == 1) { + uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]); + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); + mbedtls_sha256_update((mbedtls_sha256_context*)&self->state, bufinfo.buf, bufinfo.len); + return mp_const_none; +} + +STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + vstr_t vstr; + vstr_init_len(&vstr, 32); + mbedtls_sha256_finish((mbedtls_sha256_context*)&self->state, (unsigned char *)vstr.buf); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} + +#else + STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 0, 1, false); mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(CRYAL_SHA256_CTX)); @@ -73,7 +111,6 @@ STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) { sha256_update((CRYAL_SHA256_CTX*)self->state, bufinfo.buf, bufinfo.len); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha256_update_obj, uhashlib_sha256_update); STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) { mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); @@ -82,6 +119,9 @@ STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) { sha256_final((CRYAL_SHA256_CTX*)self->state, (byte*)vstr.buf); return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } +#endif + +MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha256_update_obj, uhashlib_sha256_update); MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha256_digest_obj, uhashlib_sha256_digest); STATIC const mp_rom_map_elem_t uhashlib_sha256_locals_dict_table[] = { From c2fb725e72f041a81b66e82ee4f7eebf55945061 Mon Sep 17 00:00:00 2001 From: Yonatan Goldschmidt Date: Sat, 9 Jun 2018 17:32:27 +0300 Subject: [PATCH 782/828] extmod/moduhashlib: Make function objects STATIC. These are not exported to anyone anyway. --- extmod/moduhashlib.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/extmod/moduhashlib.c b/extmod/moduhashlib.c index 446aa48271..b3feb23bc7 100644 --- a/extmod/moduhashlib.c +++ b/extmod/moduhashlib.c @@ -121,8 +121,8 @@ STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) { } #endif -MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha256_update_obj, uhashlib_sha256_update); -MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha256_digest_obj, uhashlib_sha256_digest); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha256_update_obj, uhashlib_sha256_update); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha256_digest_obj, uhashlib_sha256_digest); STATIC const mp_rom_map_elem_t uhashlib_sha256_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_sha256_update_obj) }, @@ -202,8 +202,8 @@ STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) { } #endif -MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha1_update_obj, uhashlib_sha1_update); -MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha1_digest_obj, uhashlib_sha1_digest); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha1_update_obj, uhashlib_sha1_update); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha1_digest_obj, uhashlib_sha1_digest); STATIC const mp_rom_map_elem_t uhashlib_sha1_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_sha1_update_obj) }, From 0501427907283a29cf61bf5fba3ab17ac81b89df Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 12 Jun 2018 13:42:43 +1000 Subject: [PATCH 783/828] esp32: Remove port-specific uhashlib implementation and use common one. Now that the common module has mbedtls support for both SHA1 and SHA256 it can now be used on this port. --- ports/esp32/Makefile | 1 - ports/esp32/moduhashlib.c | 144 ------------------------------------- ports/esp32/mpconfigport.h | 5 +- 3 files changed, 3 insertions(+), 147 deletions(-) delete mode 100644 ports/esp32/moduhashlib.c diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 929156f8a3..bb766dafca 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -167,7 +167,6 @@ SRC_C = \ modesp.c \ esp32_ulp.c \ modesp32.c \ - moduhashlib.c \ espneopixel.c \ machine_hw_spi.c \ machine_wdt.c \ diff --git a/ports/esp32/moduhashlib.c b/ports/esp32/moduhashlib.c deleted file mode 100644 index e8bc5e83c7..0000000000 --- a/ports/esp32/moduhashlib.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2014 Paul Sokolovsky - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "py/runtime.h" - -#include "mbedtls/sha256.h" -#include "mbedtls/sha1.h" - -union sha_ctxs { - mbedtls_sha256_context sha256; - mbedtls_sha1_context sha1; -}; -typedef struct _mp_obj_hash_t { - mp_obj_base_t base; - union sha_ctxs state; -} mp_obj_hash_t; - -STATIC mp_obj_t sha256_update(mp_obj_t self_in, mp_obj_t arg); -STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg); - -STATIC mp_obj_t sha256_make_new(const mp_obj_type_t *type, - size_t n_args, size_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 0, 1, false); - mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(union sha_ctxs)); - o->base.type = type; - mbedtls_sha256_init(&o->state.sha256); - mbedtls_sha256_starts(&o->state.sha256, 0); - if (n_args == 1) { - sha256_update(MP_OBJ_FROM_PTR(o), args[0]); - } - return MP_OBJ_FROM_PTR(o); -} - -STATIC mp_obj_t sha1_make_new(const mp_obj_type_t *type, - size_t n_args, size_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 0, 1, false); - mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(union sha_ctxs)); - o->base.type = type; - mbedtls_sha1_init(&o->state.sha1); - mbedtls_sha1_starts(&o->state.sha1); - if (n_args == 1) { - sha1_update(MP_OBJ_FROM_PTR(o), args[0]); - } - return MP_OBJ_FROM_PTR(o); -} - -STATIC mp_obj_t sha256_update(mp_obj_t self_in, mp_obj_t arg) { - mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); - mbedtls_sha256_update(&self->state.sha256, bufinfo.buf, bufinfo.len); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(sha256_update_obj, sha256_update); - -STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg) { - mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); - mbedtls_sha1_update(&self->state.sha1, bufinfo.buf, bufinfo.len); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(sha1_update_obj, sha1_update); - -STATIC mp_obj_t sha256_digest(mp_obj_t self_in) { - mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); - vstr_t vstr; - vstr_init_len(&vstr, 32); - mbedtls_sha256_finish(&self->state.sha256, (unsigned char *)vstr.buf); - return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); -} -MP_DEFINE_CONST_FUN_OBJ_1(sha256_digest_obj, sha256_digest); - -STATIC mp_obj_t sha1_digest(mp_obj_t self_in) { - mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); - vstr_t vstr; - vstr_init_len(&vstr, 20); - mbedtls_sha1_finish(&self->state.sha1, (unsigned char *)vstr.buf); - return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); -} -MP_DEFINE_CONST_FUN_OBJ_1(sha1_digest_obj, sha1_digest); - -STATIC const mp_rom_map_elem_t sha256_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&sha256_update_obj) }, - { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&sha256_digest_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(sha256_locals_dict, sha256_locals_dict_table); - -STATIC const mp_obj_type_t sha256_type = { - { &mp_type_type }, - .name = MP_QSTR_sha256, - .make_new = sha256_make_new, - .locals_dict = (void*)&sha256_locals_dict, -}; - -STATIC const mp_rom_map_elem_t sha1_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&sha1_update_obj) }, - { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&sha1_digest_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(sha1_locals_dict, sha1_locals_dict_table); - -STATIC const mp_obj_type_t sha1_type = { - { &mp_type_type }, - .name = MP_QSTR_sha1, - .make_new = sha1_make_new, - .locals_dict = (void*)&sha1_locals_dict, -}; - -STATIC const mp_rom_map_elem_t mp_module_hashlib_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uhashlib) }, - { MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&sha256_type) }, - { MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&sha1_type) }, -}; - -STATIC MP_DEFINE_CONST_DICT(mp_module_hashlib_globals, - mp_module_hashlib_globals_table); - -const mp_obj_module_t mp_module_uhashlib = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&mp_module_hashlib_globals, -}; diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 3c49eb24ed..963aca2efa 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -124,8 +124,9 @@ #define MICROPY_PY_URE (1) #define MICROPY_PY_UHEAPQ (1) #define MICROPY_PY_UTIMEQ (1) -#define MICROPY_PY_UHASHLIB (0) // We use the ESP32 version -#define MICROPY_PY_UHASHLIB_SHA1 (MICROPY_PY_USSL && MICROPY_SSL_AXTLS) +#define MICROPY_PY_UHASHLIB (1) +#define MICROPY_PY_UHASHLIB_SHA1 (1) +#define MICROPY_PY_UHASHLIB_SHA256 (1) #define MICROPY_PY_UBINASCII (1) #define MICROPY_PY_UBINASCII_CRC32 (1) #define MICROPY_PY_URANDOM (1) From 7ad04d17dabd503b0a79426166bcdc9e8ea4bf91 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 9 Jun 2018 15:23:13 +1000 Subject: [PATCH 784/828] py/mkrules.mk: Regenerate all qstrs when config files change. A port can define QSTR_GLOBAL_DEPENDENCIES to add extra files. --- py/mkrules.mk | 8 ++++++-- py/py.mk | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/py/mkrules.mk b/py/mkrules.mk index 850c2aa3a6..30ac520aa1 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -66,9 +66,13 @@ $(BUILD)/%.pp: %.c # to get built before we try to compile any of them. $(OBJ): | $(HEADER_BUILD)/qstrdefs.generated.h $(HEADER_BUILD)/mpversion.h -$(HEADER_BUILD)/qstr.i.last: $(SRC_QSTR) | $(HEADER_BUILD)/mpversion.h +# The logic for qstr regeneration is: +# - if anything in QSTR_GLOBAL_DEPENDENCIES is newer, then process all source files ($^) +# - else, if list of newer prerequisites ($?) is not empty, then process just these ($?) +# - else, process all source files ($^) [this covers "make -B" which can set $? to empty] +$(HEADER_BUILD)/qstr.i.last: $(SRC_QSTR) $(QSTR_GLOBAL_DEPENDENCIES) | $(HEADER_BUILD)/mpversion.h $(ECHO) "GEN $@" - $(Q)$(CPP) $(QSTR_GEN_EXTRA_CFLAGS) $(CFLAGS) $(if $?,$?,$^) >$(HEADER_BUILD)/qstr.i.last; + $(Q)$(CPP) $(QSTR_GEN_EXTRA_CFLAGS) $(CFLAGS) $(if $(filter $?,$(QSTR_GLOBAL_DEPENDENCIES)),$^,$(if $?,$?,$^)) >$(HEADER_BUILD)/qstr.i.last; $(HEADER_BUILD)/qstr.split: $(HEADER_BUILD)/qstr.i.last $(ECHO) "GEN $@" diff --git a/py/py.mk b/py/py.mk index f4b62a88af..0027fbb880 100644 --- a/py/py.mk +++ b/py/py.mk @@ -13,6 +13,9 @@ ifneq ($(QSTR_AUTOGEN_DISABLE),1) QSTR_DEFS_COLLECTED = $(HEADER_BUILD)/qstrdefs.collected.h endif +# Any files listed by this variable will cause a full regeneration of qstrs +QSTR_GLOBAL_DEPENDENCIES += $(PY_SRC)/mpconfig.h mpconfigport.h + # some code is performance bottleneck and compiled with other optimization options CSUPEROPT = -O3 From 5042d98514cb498bcc3cf22b6fcaae8ab4cb768b Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 9 Jun 2018 15:33:45 +1000 Subject: [PATCH 785/828] stm32/Makefile: Rebuild all qstrs when any board configuration changes. --- ports/stm32/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index a072e106ba..3ee0d1934b 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -14,6 +14,7 @@ include boards/$(BOARD)/mpconfigboard.mk # qstr definitions (must come before including py.mk) QSTR_DEFS = qstrdefsport.h $(BUILD)/pins_qstr.h $(BUILD)/modstm_qstr.h +QSTR_GLOBAL_DEPENDENCIES = mpconfigboard_common.h boards/$(BOARD)/mpconfigboard.h # directory containing scripts to be frozen as bytecode FROZEN_MPY_DIR ?= modules From 035906419d925bf723dba21f9fbb22ca1c8021f1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 12 Jun 2018 15:06:11 +1000 Subject: [PATCH 786/828] extmod/uos_dupterm: Use native C stream methods on dupterm object. This patch changes dupterm to call the native C stream methods on the connected stream objects, instead of calling the Python readinto/write methods. This is much more efficient for native stream objects like UART and webrepl and doesn't require allocating a special dupterm array. This change is a minor breaking change from the user's perspective because dupterm no longer accepts pure user stream objects to duplicate on. But with the recent addition of uio.IOBase it is possible to still create such classes just by inheriting from uio.IOBase, for example: import uio, uos class MyStream(uio.IOBase): def write(self, buf): # existing write implementation def readinto(self, buf): # existing readinto implementation uos.dupterm(MyStream()) --- extmod/uos_dupterm.c | 42 ++++++++++++++++-------------------------- py/mpstate.h | 1 - py/runtime.c | 1 - 3 files changed, 16 insertions(+), 28 deletions(-) diff --git a/extmod/uos_dupterm.c b/extmod/uos_dupterm.c index f77cff5770..822d640379 100644 --- a/extmod/uos_dupterm.c +++ b/extmod/uos_dupterm.c @@ -60,25 +60,29 @@ int mp_uos_dupterm_rx_chr(void) { nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { - mp_obj_t readinto_m[3]; - mp_load_method(MP_STATE_VM(dupterm_objs[idx]), MP_QSTR_readinto, readinto_m); - readinto_m[2] = MP_STATE_VM(dupterm_arr_obj); - mp_obj_t res = mp_call_method_n_kw(1, 0, readinto_m); - if (res == mp_const_none) { - nlr_pop(); - } else if (res == MP_OBJ_NEW_SMALL_INT(0)) { + byte buf[1]; + int errcode; + const mp_stream_p_t *stream_p = mp_get_stream_raise(MP_STATE_VM(dupterm_objs[idx]), MP_STREAM_OP_READ); + mp_uint_t out_sz = stream_p->read(MP_STATE_VM(dupterm_objs[idx]), buf, 1, &errcode); + if (out_sz == 0) { nlr_pop(); mp_uos_deactivate(idx, "dupterm: EOF received, deactivating\n", MP_OBJ_NULL); + } else if (out_sz == MP_STREAM_ERROR) { + // errcode is valid + if (mp_is_nonblocking_error(errcode)) { + nlr_pop(); + } else { + mp_raise_OSError(errcode); + } } else { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(MP_STATE_VM(dupterm_arr_obj), &bufinfo, MP_BUFFER_READ); + // read 1 byte nlr_pop(); - if (*(byte*)bufinfo.buf == mp_interrupt_char) { + if (buf[0] == mp_interrupt_char) { // Signal keyboard interrupt to be raised as soon as the VM resumes mp_keyboard_interrupt(); return -2; } - return *(byte*)bufinfo.buf; + return buf[0]; } } else { mp_uos_deactivate(idx, "dupterm: Exception in read() method, deactivating: ", nlr.ret_val); @@ -96,18 +100,7 @@ void mp_uos_dupterm_tx_strn(const char *str, size_t len) { } nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { - mp_obj_t write_m[3]; - mp_load_method(MP_STATE_VM(dupterm_objs[idx]), MP_QSTR_write, write_m); - - mp_obj_array_t *arr = MP_OBJ_TO_PTR(MP_STATE_VM(dupterm_arr_obj)); - void *org_items = arr->items; - arr->items = (void*)str; - arr->len = len; - write_m[2] = MP_STATE_VM(dupterm_arr_obj); - mp_call_method_n_kw(1, 0, write_m); - arr = MP_OBJ_TO_PTR(MP_STATE_VM(dupterm_arr_obj)); - arr->items = org_items; - arr->len = 1; + mp_stream_write(MP_STATE_VM(dupterm_objs[idx]), str, len, MP_STREAM_RW_WRITE); nlr_pop(); } else { mp_uos_deactivate(idx, "dupterm: Exception in write() method, deactivating: ", nlr.ret_val); @@ -133,9 +126,6 @@ STATIC mp_obj_t mp_uos_dupterm(size_t n_args, const mp_obj_t *args) { MP_STATE_VM(dupterm_objs[idx]) = MP_OBJ_NULL; } else { MP_STATE_VM(dupterm_objs[idx]) = args[0]; - if (MP_STATE_VM(dupterm_arr_obj) == MP_OBJ_NULL) { - MP_STATE_VM(dupterm_arr_obj) = mp_obj_new_bytearray(1, ""); - } } return previous_obj; diff --git a/py/mpstate.h b/py/mpstate.h index 199fd2cb63..8c3b710cbd 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -171,7 +171,6 @@ typedef struct _mp_state_vm_t { #if MICROPY_PY_OS_DUPTERM mp_obj_t dupterm_objs[MICROPY_PY_OS_DUPTERM]; - mp_obj_t dupterm_arr_obj; #endif #if MICROPY_PY_LWIP_SLIP diff --git a/py/runtime.c b/py/runtime.c index 8f10630768..a2dac46a42 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -108,7 +108,6 @@ void mp_init(void) { for (size_t i = 0; i < MICROPY_PY_OS_DUPTERM; ++i) { MP_STATE_VM(dupterm_objs[i]) = MP_OBJ_NULL; } - MP_STATE_VM(dupterm_arr_obj) = MP_OBJ_NULL; #endif #if MICROPY_FSUSERMOUNT From d11fb09333ab96ec1b4e9d10d74961caf1172153 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 13 Jun 2018 13:16:21 +1000 Subject: [PATCH 787/828] extmod/modussl_axtls: Fix __del__ to point to mp_stream_close_obj. --- extmod/modussl_axtls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/modussl_axtls.c b/extmod/modussl_axtls.c index 689d33305a..475d3f0ea4 100644 --- a/extmod/modussl_axtls.c +++ b/extmod/modussl_axtls.c @@ -212,7 +212,7 @@ STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, #if MICROPY_PY_USSL_FINALISER - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, #endif }; From cf1509c911a1e1f983538105592575a8a520341f Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 13 Jun 2018 14:13:34 +1000 Subject: [PATCH 788/828] esp32/fatfs_port: Implement get_fattime so FAT files have a timestamp. Fixes issue #3859. --- ports/esp32/fatfs_port.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/ports/esp32/fatfs_port.c b/ports/esp32/fatfs_port.c index b3690a01fb..880324ed82 100644 --- a/ports/esp32/fatfs_port.c +++ b/ports/esp32/fatfs_port.c @@ -26,20 +26,15 @@ * THE SOFTWARE. */ -#include "py/obj.h" +#include #include "lib/oofatfs/ff.h" #include "timeutils.h" -//#include "modmachine.h" DWORD get_fattime(void) { - - // TODO: Optimize division (there's no HW division support on ESP8266, - // so it's expensive). - //uint32_t secs = (uint32_t)(pyb_rtc_get_us_since_2000() / 1000000); - uint32_t secs = 0; - + struct timeval tv; + gettimeofday(&tv, NULL); timeutils_struct_time_t tm; - timeutils_seconds_since_2000_to_struct_time(secs, &tm); + timeutils_seconds_since_2000_to_struct_time(tv.tv_sec, &tm); return (((DWORD)(tm.tm_year - 1980) << 25) | ((DWORD)tm.tm_mon << 21) | ((DWORD)tm.tm_mday << 16) | ((DWORD)tm.tm_hour << 11) | ((DWORD)tm.tm_min << 5) | ((DWORD)tm.tm_sec >> 1)); From 86fe73beb99686ea15787f0603ad6f10a642054c Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Jun 2018 14:09:10 +1000 Subject: [PATCH 789/828] drivers/memory/spiflash: Move cache buffer to user-provided config. This patch removes the global cache variables from the SPI flash driver and now requires the user to provide the cache memory themselves, via the SPI flash configuration struct. This allows to either have a shared cache for multiple SPI flash devices (by sharing a mp_spiflash_cache_t struct), or have a single cache per device (or a mix of these options). To configure the cache use: mp_spiflash_cache_t spi_bdev_cache; const mp_spiflash_config_t spiflash_config = // any bus options .cache = &spi_bdev_cache, }; --- drivers/memory/spiflash.c | 69 ++++++++++++++++++++------------------- drivers/memory/spiflash.h | 13 ++++++++ 2 files changed, 48 insertions(+), 34 deletions(-) diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c index d72603f648..0cc926b79d 100644 --- a/drivers/memory/spiflash.c +++ b/drivers/memory/spiflash.c @@ -48,12 +48,7 @@ #define WAIT_SR_TIMEOUT (1000000) #define PAGE_SIZE (256) // maximum bytes we can write in one SPI transfer -#define SECTOR_SIZE (4096) // size of erase sector - -// Note: this code is not reentrant with this shared buffer -STATIC uint8_t buf[SECTOR_SIZE] __attribute__((aligned(4))); -STATIC mp_spiflash_t *bufuser; // current user of buf -STATIC uint32_t bufsec; // current sector stored in buf; 0xffffffff if invalid +#define SECTOR_SIZE MP_SPIFLASH_ERASE_BLOCK_SIZE STATIC void mp_spiflash_acquire_bus(mp_spiflash_t *self) { const mp_spiflash_config_t *c = self->config; @@ -231,15 +226,16 @@ void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *d return; } mp_spiflash_acquire_bus(self); - if (bufuser == self && bufsec != 0xffffffff) { + mp_spiflash_cache_t *cache = self->config->cache; + if (cache->user == self && cache->block != 0xffffffff) { uint32_t bis = addr / SECTOR_SIZE; uint32_t bie = (addr + len - 1) / SECTOR_SIZE; - if (bis <= bufsec && bufsec <= bie) { + if (bis <= cache->block && cache->block <= bie) { // Read straddles current buffer size_t rest = 0; - if (bis < bufsec) { + if (bis < cache->block) { // Read direct from flash for first part - rest = bufsec * SECTOR_SIZE - addr; + rest = cache->block * SECTOR_SIZE - addr; mp_spiflash_read_data(self, addr, rest, dest); len -= rest; dest += rest; @@ -250,7 +246,7 @@ void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *d if (rest > len) { rest = len; } - memcpy(dest, &buf[offset], rest); + memcpy(dest, &cache->buf[offset], rest); len -= rest; if (len == 0) { mp_spiflash_release_bus(self); @@ -273,15 +269,17 @@ STATIC void mp_spiflash_flush_internal(mp_spiflash_t *self) { self->flags &= ~1; + mp_spiflash_cache_t *cache = self->config->cache; + // Erase sector - int ret = mp_spiflash_erase_sector(self, bufsec * SECTOR_SIZE); + int ret = mp_spiflash_erase_sector(self, cache->block * SECTOR_SIZE); if (ret != 0) { return; } // Write for (int i = 0; i < 16; i += 1) { - int ret = mp_spiflash_write_page(self, bufsec * SECTOR_SIZE + i * PAGE_SIZE, buf + i * PAGE_SIZE); + int ret = mp_spiflash_write_page(self, cache->block * SECTOR_SIZE + i * PAGE_SIZE, cache->buf + i * PAGE_SIZE); if (ret != 0) { return; } @@ -302,35 +300,37 @@ STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len addr = sec << 12; // Restriction for now, so we don't need to erase multiple pages - if (offset + len > sizeof(buf)) { + if (offset + len > SECTOR_SIZE) { printf("mp_spiflash_write_part: len is too large\n"); return -MP_EIO; } + mp_spiflash_cache_t *cache = self->config->cache; + // Acquire the sector buffer - if (bufuser != self) { - if (bufuser != NULL) { - mp_spiflash_flush(bufuser); + if (cache->user != self) { + if (cache->user != NULL) { + mp_spiflash_flush(cache->user); } - bufuser = self; - bufsec = 0xffffffff; + cache->user = self; + cache->block = 0xffffffff; } - if (bufsec != sec) { + if (cache->block != sec) { // Read sector #if USE_WR_DELAY - if (bufsec != 0xffffffff) { + if (cache->block != 0xffffffff) { mp_spiflash_flush_internal(self); } #endif - mp_spiflash_read_data(self, addr, SECTOR_SIZE, buf); + mp_spiflash_read_data(self, addr, SECTOR_SIZE, cache->buf); } #if USE_WR_DELAY - bufsec = sec; + cache->block = sec; // Just copy to buffer - memcpy(buf + offset, src, len); + memcpy(cache->buf + offset, src, len); // And mark dirty self->flags |= 1; @@ -338,8 +338,8 @@ STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len uint32_t dirty = 0; for (size_t i = 0; i < len; ++i) { - if (buf[offset + i] != src[i]) { - if (buf[offset + i] != 0xff) { + if (cache->buf[offset + i] != src[i]) { + if (cache->buf[offset + i] != 0xff) { // Erase sector int ret = mp_spiflash_erase_sector(self, addr); if (ret != 0) { @@ -353,14 +353,14 @@ STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len } } - bufsec = sec; + cache->block = sec; // Copy new block into buffer - memcpy(buf + offset, src, len); + memcpy(cache->buf + offset, src, len); // Write sector in pages of 256 bytes for (size_t i = 0; i < 16; ++i) { if (dirty & (1 << i)) { - int ret = mp_spiflash_write_page(self, addr + i * PAGE_SIZE, buf + i * PAGE_SIZE); + int ret = mp_spiflash_write_page(self, addr + i * PAGE_SIZE, cache->buf + i * PAGE_SIZE); if (ret != 0) { return ret; } @@ -378,16 +378,17 @@ int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint mp_spiflash_acquire_bus(self); - if (bufuser == self && bis <= bufsec && bie >= bufsec) { + mp_spiflash_cache_t *cache = self->config->cache; + if (cache->user == self && bis <= cache->block && bie >= cache->block) { // Write straddles current buffer uint32_t pre; uint32_t offset; - if (bufsec * SECTOR_SIZE >= addr) { - pre = bufsec * SECTOR_SIZE - addr; + if (cache->block * SECTOR_SIZE >= addr) { + pre = cache->block * SECTOR_SIZE - addr; offset = 0; } else { pre = 0; - offset = addr - bufsec * SECTOR_SIZE; + offset = addr - cache->block * SECTOR_SIZE; } // Write buffered part first @@ -397,7 +398,7 @@ int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint len = len_in_buf - (SECTOR_SIZE - offset); len_in_buf = SECTOR_SIZE - offset; } - memcpy(&buf[offset], &src[pre], len_in_buf); + memcpy(&cache->buf[offset], &src[pre], len_in_buf); self->flags |= 1; // Mark dirty // Write part before buffer sector diff --git a/drivers/memory/spiflash.h b/drivers/memory/spiflash.h index 03bad5296a..66e7906cca 100644 --- a/drivers/memory/spiflash.h +++ b/drivers/memory/spiflash.h @@ -29,11 +29,23 @@ #include "drivers/bus/spi.h" #include "drivers/bus/qspi.h" +#define MP_SPIFLASH_ERASE_BLOCK_SIZE (4096) // must be a power of 2 + enum { MP_SPIFLASH_BUS_SPI, MP_SPIFLASH_BUS_QSPI, }; +struct _mp_spiflash_t; + +// A cache must be provided by the user in the config struct. The same cache +// struct can be shared by multiple SPI flash instances. +typedef struct _mp_spiflash_cache_t { + uint8_t buf[MP_SPIFLASH_ERASE_BLOCK_SIZE] __attribute__((aligned(4))); + struct _mp_spiflash_t *user; // current user of buf, for shared use + uint32_t block; // current block stored in buf; 0xffffffff if invalid +} mp_spiflash_cache_t; + typedef struct _mp_spiflash_config_t { uint32_t bus_kind; union { @@ -47,6 +59,7 @@ typedef struct _mp_spiflash_config_t { const mp_qspi_proto_t *proto; } u_qspi; } bus; + mp_spiflash_cache_t *cache; } mp_spiflash_config_t; typedef struct _mp_spiflash_t { From 335d26b27d238cca9b4447a46d187d4c6f573d3a Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Jun 2018 14:15:10 +1000 Subject: [PATCH 790/828] stm32/boards/STM32L476DISC: Update SPI flash config for cache change. --- ports/stm32/boards/STM32L476DISC/bdev.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ports/stm32/boards/STM32L476DISC/bdev.c b/ports/stm32/boards/STM32L476DISC/bdev.c index 6b353a2f90..01f06b8b1d 100644 --- a/ports/stm32/boards/STM32L476DISC/bdev.c +++ b/ports/stm32/boards/STM32L476DISC/bdev.c @@ -2,7 +2,7 @@ // External SPI flash uses standard SPI interface -const mp_soft_spi_obj_t soft_spi_bus = { +STATIC const mp_soft_spi_obj_t soft_spi_bus = { .delay_half = MICROPY_HW_SOFTSPI_MIN_DELAY, .polarity = 0, .phase = 0, @@ -11,11 +11,14 @@ const mp_soft_spi_obj_t soft_spi_bus = { .miso = MICROPY_HW_SPIFLASH_MISO, }; +STATIC mp_spiflash_cache_t spi_bdev_cache; + const mp_spiflash_config_t spiflash_config = { .bus_kind = MP_SPIFLASH_BUS_SPI, .bus.u_spi.cs = MICROPY_HW_SPIFLASH_CS, .bus.u_spi.data = (void*)&soft_spi_bus, .bus.u_spi.proto = &mp_soft_spi_proto, + .cache = &spi_bdev_cache, }; spi_bdev_t spi_bdev; From cc5a94044a670f5acccefa8e04a38e81d882e087 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Jun 2018 15:36:27 +1000 Subject: [PATCH 791/828] drivers/memory/spiflash: Rename functions to indicate they use cache. This patch renames the existing SPI flash API functions to reflect the fact that the go through the cache: mp_spiflash_flush -> mp_spiflash_cache_flush mp_spiflash_read -> mp_spiflash_cached_read mp_spiflash_write -> mp_spiflash_cached_write --- drivers/memory/spiflash.c | 25 ++++++++++++++----------- drivers/memory/spiflash.h | 8 +++++--- ports/stm32/spibdev.c | 8 ++++---- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c index 0cc926b79d..d750d87bed 100644 --- a/drivers/memory/spiflash.c +++ b/drivers/memory/spiflash.c @@ -221,7 +221,10 @@ STATIC int mp_spiflash_write_page(mp_spiflash_t *self, uint32_t addr, const uint return mp_spiflash_wait_wip0(self); } -void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) { +/******************************************************************************/ +// Interface functions that use the cache + +void mp_spiflash_cached_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) { if (len == 0) { return; } @@ -261,7 +264,7 @@ void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *d mp_spiflash_release_bus(self); } -STATIC void mp_spiflash_flush_internal(mp_spiflash_t *self) { +STATIC void mp_spiflash_cache_flush_internal(mp_spiflash_t *self) { #if USE_WR_DELAY if (!(self->flags & 1)) { return; @@ -287,13 +290,13 @@ STATIC void mp_spiflash_flush_internal(mp_spiflash_t *self) { #endif } -void mp_spiflash_flush(mp_spiflash_t *self) { +void mp_spiflash_cache_flush(mp_spiflash_t *self) { mp_spiflash_acquire_bus(self); - mp_spiflash_flush_internal(self); + mp_spiflash_cache_flush_internal(self); mp_spiflash_release_bus(self); } -STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { +STATIC int mp_spiflash_cached_write_part(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { // Align to 4096 sector uint32_t offset = addr & 0xfff; uint32_t sec = addr >> 12; @@ -301,7 +304,7 @@ STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len // Restriction for now, so we don't need to erase multiple pages if (offset + len > SECTOR_SIZE) { - printf("mp_spiflash_write_part: len is too large\n"); + printf("mp_spiflash_cached_write_part: len is too large\n"); return -MP_EIO; } @@ -310,7 +313,7 @@ STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len // Acquire the sector buffer if (cache->user != self) { if (cache->user != NULL) { - mp_spiflash_flush(cache->user); + mp_spiflash_cache_flush(cache->user); } cache->user = self; cache->block = 0xffffffff; @@ -320,7 +323,7 @@ STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len // Read sector #if USE_WR_DELAY if (cache->block != 0xffffffff) { - mp_spiflash_flush_internal(self); + mp_spiflash_cache_flush_internal(self); } #endif mp_spiflash_read_data(self, addr, SECTOR_SIZE, cache->buf); @@ -372,7 +375,7 @@ STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len return 0; // success } -int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { +int mp_spiflash_cached_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { uint32_t bis = addr / SECTOR_SIZE; uint32_t bie = (addr + len - 1) / SECTOR_SIZE; @@ -407,7 +410,7 @@ int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint if (rest == 0) { rest = SECTOR_SIZE; } - int ret = mp_spiflash_write_part(self, addr, rest, src); + int ret = mp_spiflash_cached_write_part(self, addr, rest, src); if (ret != 0) { mp_spiflash_release_bus(self); return ret; @@ -428,7 +431,7 @@ int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint if (rest > len) { rest = len; } - int ret = mp_spiflash_write_part(self, addr, rest, src); + int ret = mp_spiflash_cached_write_part(self, addr, rest, src); if (ret != 0) { mp_spiflash_release_bus(self); return ret; diff --git a/drivers/memory/spiflash.h b/drivers/memory/spiflash.h index 66e7906cca..4837fe3f99 100644 --- a/drivers/memory/spiflash.h +++ b/drivers/memory/spiflash.h @@ -68,8 +68,10 @@ typedef struct _mp_spiflash_t { } mp_spiflash_t; void mp_spiflash_init(mp_spiflash_t *self); -void mp_spiflash_flush(mp_spiflash_t *self); -void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest); -int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src); + +// These functions use the cache (which must already be configured) +void mp_spiflash_cache_flush(mp_spiflash_t *self); +void mp_spiflash_cached_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest); +int mp_spiflash_cached_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src); #endif // MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H diff --git a/ports/stm32/spibdev.c b/ports/stm32/spibdev.c index b73058c6ab..368e639665 100644 --- a/ports/stm32/spibdev.c +++ b/ports/stm32/spibdev.c @@ -42,7 +42,7 @@ int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) { case BDEV_IOCTL_IRQ_HANDLER: if ((bdev->spiflash.flags & 1) && HAL_GetTick() - bdev->flash_tick_counter_last_write >= 1000) { - mp_spiflash_flush(&bdev->spiflash); + mp_spiflash_cache_flush(&bdev->spiflash); led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off } return 0; @@ -51,7 +51,7 @@ int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) { if (bdev->spiflash.flags & 1) { // we must disable USB irqs to prevent MSC contention with SPI flash uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - mp_spiflash_flush(&bdev->spiflash); + mp_spiflash_cache_flush(&bdev->spiflash); led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off restore_irq_pri(basepri); } @@ -63,7 +63,7 @@ int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) { int spi_bdev_readblocks(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { // we must disable USB irqs to prevent MSC contention with SPI flash uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - mp_spiflash_read(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, dest); + mp_spiflash_cached_read(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, dest); restore_irq_pri(basepri); return 0; @@ -72,7 +72,7 @@ int spi_bdev_readblocks(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uin int spi_bdev_writeblocks(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { // we must disable USB irqs to prevent MSC contention with SPI flash uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - int ret = mp_spiflash_write(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, src); + int ret = mp_spiflash_cached_write(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, src); if (bdev->spiflash.flags & 1) { led_state(PYB_LED_RED, 1); // indicate a dirty cache with LED on bdev->flash_tick_counter_last_write = HAL_GetTick(); From b78ca32476ba666412a9ec44a5453094fbf0dbd7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Jun 2018 15:39:46 +1000 Subject: [PATCH 792/828] drivers/memory/spiflash: Add functions for direct erase/read/write. These new API functions do not use the cache. --- drivers/memory/spiflash.c | 56 ++++++++++++++++++++++++++++++++++----- drivers/memory/spiflash.h | 7 ++++- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c index d750d87bed..c0b55591be 100644 --- a/drivers/memory/spiflash.c +++ b/drivers/memory/spiflash.c @@ -187,7 +187,7 @@ void mp_spiflash_init(mp_spiflash_t *self) { mp_spiflash_release_bus(self); } -STATIC int mp_spiflash_erase_sector(mp_spiflash_t *self, uint32_t addr) { +STATIC int mp_spiflash_erase_block_internal(mp_spiflash_t *self, uint32_t addr) { // enable writes mp_spiflash_write_cmd(self, CMD_WREN); @@ -204,7 +204,7 @@ STATIC int mp_spiflash_erase_sector(mp_spiflash_t *self, uint32_t addr) { return mp_spiflash_wait_wip0(self); } -STATIC int mp_spiflash_write_page(mp_spiflash_t *self, uint32_t addr, const uint8_t *src) { +STATIC int mp_spiflash_write_page(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { // enable writes mp_spiflash_write_cmd(self, CMD_WREN); @@ -215,12 +215,53 @@ STATIC int mp_spiflash_write_page(mp_spiflash_t *self, uint32_t addr, const uint } // write the page - mp_spiflash_write_cmd_addr_data(self, CMD_WRITE, addr, PAGE_SIZE, src); + mp_spiflash_write_cmd_addr_data(self, CMD_WRITE, addr, len, src); // wait WIP=0 return mp_spiflash_wait_wip0(self); } +/******************************************************************************/ +// Interface functions that go direct to the SPI flash device + +int mp_spiflash_erase_block(mp_spiflash_t *self, uint32_t addr) { + mp_spiflash_acquire_bus(self); + int ret = mp_spiflash_erase_block_internal(self, addr); + mp_spiflash_release_bus(self); + return ret; +} + +void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) { + if (len == 0) { + return; + } + mp_spiflash_acquire_bus(self); + mp_spiflash_read_data(self, addr, len, dest); + mp_spiflash_release_bus(self); +} + +int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { + mp_spiflash_acquire_bus(self); + int ret = 0; + uint32_t offset = addr & (PAGE_SIZE - 1); + while (len) { + size_t rest = PAGE_SIZE - offset; + if (rest > len) { + rest = len; + } + ret = mp_spiflash_write_page(self, addr, rest, src); + if (ret != 0) { + break; + } + len -= rest; + addr += rest; + src += rest; + offset = 0; + } + mp_spiflash_release_bus(self); + return ret; +} + /******************************************************************************/ // Interface functions that use the cache @@ -275,14 +316,15 @@ STATIC void mp_spiflash_cache_flush_internal(mp_spiflash_t *self) { mp_spiflash_cache_t *cache = self->config->cache; // Erase sector - int ret = mp_spiflash_erase_sector(self, cache->block * SECTOR_SIZE); + int ret = mp_spiflash_erase_block_internal(self, cache->block * SECTOR_SIZE); if (ret != 0) { return; } // Write for (int i = 0; i < 16; i += 1) { - int ret = mp_spiflash_write_page(self, cache->block * SECTOR_SIZE + i * PAGE_SIZE, cache->buf + i * PAGE_SIZE); + uint32_t addr = cache->block * SECTOR_SIZE + i * PAGE_SIZE; + int ret = mp_spiflash_write_page(self, addr, PAGE_SIZE, cache->buf + i * PAGE_SIZE); if (ret != 0) { return; } @@ -344,7 +386,7 @@ STATIC int mp_spiflash_cached_write_part(mp_spiflash_t *self, uint32_t addr, siz if (cache->buf[offset + i] != src[i]) { if (cache->buf[offset + i] != 0xff) { // Erase sector - int ret = mp_spiflash_erase_sector(self, addr); + int ret = mp_spiflash_erase_block_internal(self, addr); if (ret != 0) { return ret; } @@ -363,7 +405,7 @@ STATIC int mp_spiflash_cached_write_part(mp_spiflash_t *self, uint32_t addr, siz // Write sector in pages of 256 bytes for (size_t i = 0; i < 16; ++i) { if (dirty & (1 << i)) { - int ret = mp_spiflash_write_page(self, addr + i * PAGE_SIZE, cache->buf + i * PAGE_SIZE); + int ret = mp_spiflash_write_page(self, addr + i * PAGE_SIZE, PAGE_SIZE, cache->buf + i * PAGE_SIZE); if (ret != 0) { return ret; } diff --git a/drivers/memory/spiflash.h b/drivers/memory/spiflash.h index 4837fe3f99..a5b8a1dcae 100644 --- a/drivers/memory/spiflash.h +++ b/drivers/memory/spiflash.h @@ -59,7 +59,7 @@ typedef struct _mp_spiflash_config_t { const mp_qspi_proto_t *proto; } u_qspi; } bus; - mp_spiflash_cache_t *cache; + mp_spiflash_cache_t *cache; // can be NULL if cache functions not used } mp_spiflash_config_t; typedef struct _mp_spiflash_t { @@ -69,6 +69,11 @@ typedef struct _mp_spiflash_t { void mp_spiflash_init(mp_spiflash_t *self); +// These functions go direct to the SPI flash device +int mp_spiflash_erase_block(mp_spiflash_t *self, uint32_t addr); +void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest); +int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src); + // These functions use the cache (which must already be configured) void mp_spiflash_cache_flush(mp_spiflash_t *self); void mp_spiflash_cached_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest); From 37a7257affa5e1ad449d911797dfc4b9e46677b3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 15 Jun 2018 10:50:08 +1000 Subject: [PATCH 793/828] stm32/timer: Support TIM1 on F0 MCUs. --- ports/stm32/stm32_it.c | 6 ++++++ ports/stm32/timer.c | 6 ++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index c09ffce767..a2a8d0f2e5 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -610,6 +610,12 @@ void EXTI4_15_IRQHandler(void) { IRQ_EXIT(EXTI4_15_IRQn); } +void TIM1_BRK_UP_TRG_COM_IRQHandler(void) { + IRQ_ENTER(TIM1_BRK_UP_TRG_COM_IRQn); + timer_irq_handler(1); + IRQ_EXIT(TIM1_BRK_UP_TRG_COM_IRQn); +} + #endif void TIM1_BRK_TIM9_IRQHandler(void) { diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c index cc00f7a887..cf198e8651 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -655,11 +655,13 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons return mp_const_none; } -// This table encodes the timer instance and irq number. +// This table encodes the timer instance and irq number (for the update irq). // It assumes that timer instance pointer has the lower 8 bits cleared. #define TIM_ENTRY(id, irq) [id - 1] = (uint32_t)TIM##id | irq STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = { - #if defined(STM32F4) || defined(STM32F7) + #if defined(STM32F0) + TIM_ENTRY(1, TIM1_BRK_UP_TRG_COM_IRQn), + #elif defined(STM32F4) || defined(STM32F7) TIM_ENTRY(1, TIM1_UP_TIM10_IRQn), #elif defined(STM32L4) TIM_ENTRY(1, TIM1_UP_TIM16_IRQn), From bc5e8a2cb6f17bc5a9fec108a2421adc77f5cb3c Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 15 Jun 2018 14:10:53 +1000 Subject: [PATCH 794/828] stm32/i2c: Fix num_acks calculation in i2c_write for F0 and F7 MCU's. Due to buffering of outgoing bytes on the I2C bus, detection of a NACK using the ISR_NACKF flag needs to account for the case where ISR_NACKF corresponds to the previous-to-previous byte. --- ports/stm32/i2c.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index e0eea90ab7..109b9418f8 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -421,8 +421,13 @@ int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len) { if ((ret = i2c_wait_isr_set(i2c, I2C_ISR_TCR | I2C_ISR_TC | I2C_ISR_STOPF))) { return ret; } - if (i2c->ISR & I2C_ISR_NACKF) { + uint32_t isr = i2c->ISR; + if (isr & I2C_ISR_NACKF) { // Slave did not respond to byte so stop sending + if (!(isr & I2C_ISR_TXE)) { + // The TXDR is still full so the byte previous to that wasn't actually ACK'd + --num_acks; + } break; } ++num_acks; From 7be4a23c0cccbcd9096d57235f32c5c2e02f6604 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 15 Jun 2018 14:15:31 +1000 Subject: [PATCH 795/828] stm32/i2cslave: Fix ordering of event callbacks in slave IRQ handler. It's possible (at least on F4 MCU's) to have RXNE and STOPF set at the same time during a call to the slave IRQ handler. In such cases RXNE should be handled before STOPF so that all bytes are processed before i2c_slave_process_rx_end() is called. --- ports/stm32/i2cslave.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ports/stm32/i2cslave.c b/ports/stm32/i2cslave.c index f8ff19cd6c..473f0c8c55 100644 --- a/ports/stm32/i2cslave.c +++ b/ports/stm32/i2cslave.c @@ -44,6 +44,12 @@ void i2c_slave_ev_irq_handler(i2c_slave_t *i2c) { uint32_t sr2 = i2c->SR2; i2c_slave_process_addr_match((sr2 >> I2C_SR2_TRA_Pos) & 1); } + if (sr1 & I2C_SR1_TXE) { + i2c->DR = i2c_slave_process_tx_byte(); + } + if (sr1 & I2C_SR1_RXNE) { + i2c_slave_process_rx_byte(i2c->DR); + } if (sr1 & I2C_SR1_STOPF) { // STOPF only set at end of RX mode (in TX mode AF is set on NACK) // Read of SR1, write CR1 needed to clear STOPF bit @@ -52,12 +58,6 @@ void i2c_slave_ev_irq_handler(i2c_slave_t *i2c) { i2c_slave_process_rx_end(); i2c->CR1 |= I2C_CR1_ACK; } - if (sr1 & I2C_SR1_TXE) { - i2c->DR = i2c_slave_process_tx_byte(); - } - if (sr1 & I2C_SR1_RXNE) { - i2c_slave_process_rx_byte(i2c->DR); - } } #elif defined(STM32F7) @@ -79,6 +79,12 @@ void i2c_slave_ev_irq_handler(i2c_slave_t *i2c) { i2c->ICR = I2C_ICR_ADDRCF; i2c_slave_process_addr_match(0); } + if (isr & I2C_ISR_TXIS) { + i2c->TXDR = i2c_slave_process_tx_byte(); + } + if (isr & I2C_ISR_RXNE) { + i2c_slave_process_rx_byte(i2c->RXDR); + } if (isr & I2C_ISR_STOPF) { // STOPF only set for STOP condition, not a repeated START i2c->ICR = I2C_ICR_STOPCF; @@ -90,12 +96,6 @@ void i2c_slave_ev_irq_handler(i2c_slave_t *i2c) { } i2c->OAR1 |= I2C_OAR1_OA1EN; } - if (isr & I2C_ISR_TXIS) { - i2c->TXDR = i2c_slave_process_tx_byte(); - } - if (isr & I2C_ISR_RXNE) { - i2c_slave_process_rx_byte(i2c->RXDR); - } } #endif From d61d119c944f5abd9326b30063b54b07c70dfa75 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 15 Jun 2018 16:23:53 +1000 Subject: [PATCH 796/828] esp32: Update to latest ESP IDF. --- ports/esp32/Makefile | 15 ++++++++---- ports/esp32/esp32.custom_common.ld | 37 ++++++++++++++++++++++++++---- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index bb766dafca..b0baa0dca1 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -21,7 +21,7 @@ FLASH_FREQ ?= 40m FLASH_SIZE ?= 4MB CROSS_COMPILE ?= xtensa-esp32-elf- -ESPIDF_SUPHASH := 1f7b41e206646417adc572da928175d33c986bd3 +ESPIDF_SUPHASH := 9a55b42f0841b3d38a61089b1dda4bf28135decd # paths to ESP IDF and its components ifeq ($(ESPIDF),) @@ -93,6 +93,7 @@ INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include INC_ESPCOMP += -I$(ESPCOMP)/app_trace/include INC_ESPCOMP += -I$(ESPCOMP)/app_update/include INC_ESPCOMP += -I$(ESPCOMP)/pthread/include +INC_ESPCOMP += -I$(ESPCOMP)/smartconfig_ack/include # these flags are common to C and C++ compilation CFLAGS_COMMON = -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfields \ @@ -271,7 +272,7 @@ ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\ intr_alloc.o \ dport_access.o \ wifi_init.o \ - wifi_internal.o \ + wifi_os_adapter.o \ sleep_modes.o \ spiram.o \ spiram_psram.o \ @@ -291,6 +292,7 @@ ESPIDF_SOC_O = $(addprefix $(ESPCOMP)/soc/,\ esp32/rtc_sleep.o \ esp32/rtc_time.o \ esp32/soc_memory_layout.o \ + esp32/spi_periph.o \ ) ESPIDF_CXX_O = $(addprefix $(ESPCOMP)/cxx/,\ @@ -331,7 +333,7 @@ $(BUILD)/$(ESPCOMP)/freertos/portasm.o: CFLAGS = $(CFLAGS_ASM) $(BUILD)/$(ESPCOMP)/freertos/xtensa_context.o: CFLAGS = $(CFLAGS_ASM) $(BUILD)/$(ESPCOMP)/freertos/xtensa_intr_asm.o: CFLAGS = $(CFLAGS_ASM) $(BUILD)/$(ESPCOMP)/freertos/xtensa_vectors.o: CFLAGS = $(CFLAGS_ASM) -$(BUILD)/$(ESPCOMP)/freertos/%.o: CFLAGS = $(CFLAGS_BASE) -I. $(INC_ESPCOMP) -I$(ESPCOMP)/freertos/include/freertos +$(BUILD)/$(ESPCOMP)/freertos/%.o: CFLAGS = $(CFLAGS_BASE) -I. $(INC_ESPCOMP) -I$(ESPCOMP)/freertos/include/freertos -D_ESP_FREERTOS_INTERNAL ESPIDF_FREERTOS_O = $(addprefix $(ESPCOMP)/freertos/,\ croutine.o \ event_groups.o \ @@ -429,6 +431,10 @@ ESPIDF_NVS_FLASH_O = $(addprefix $(ESPCOMP)/nvs_flash/,\ ESPIDF_OPENSSL_O = $(addprefix $(ESPCOMP)/openssl/,\ ) +ESPIDF_SMARTCONFIG_ACK_O = $(addprefix $(ESPCOMP)/smartconfig_ack/,\ + smartconfig_ack.o \ + ) + ESPIDF_SPI_FLASH_O = $(addprefix $(ESPCOMP)/spi_flash/,\ flash_mmap.o \ partition.o \ @@ -629,6 +635,7 @@ OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_APP_UPDATE_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NGHTTP_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NVS_FLASH_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_OPENSSL_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SMARTCONFIG_ACK_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SPI_FLASH_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ULP_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_WPA_SUPPLICANT_O)) @@ -666,7 +673,7 @@ APP_LD_ARGS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc APP_LD_ARGS += -L$(dir $(LIBSTDCXX_FILE_NAME)) -lstdc++ APP_LD_ARGS += $(LIBC_LIBM) APP_LD_ARGS += $(ESPCOMP)/esp32/libhal.a -APP_LD_ARGS += -L$(ESPCOMP)/esp32/lib -lcore -lnet80211 -lphy -lrtc -lpp -lwpa -lsmartconfig -lcoexist -lwps -lwpa2 +APP_LD_ARGS += -L$(ESPCOMP)/esp32/lib -lcore -lmesh -lnet80211 -lphy -lrtc -lpp -lwpa -lsmartconfig -lcoexist -lwps -lwpa2 APP_LD_ARGS += $(OBJ) APP_LD_ARGS += --end-group diff --git a/ports/esp32/esp32.custom_common.ld b/ports/esp32/esp32.custom_common.ld index f49ff9b207..716e9ac1d8 100644 --- a/ports/esp32/esp32.custom_common.ld +++ b/ports/esp32/esp32.custom_common.ld @@ -11,7 +11,7 @@ SECTIONS . = ALIGN(4); *(.rtc.literal .rtc.text) *rtc_wake_stub*.o(.literal .text .literal.* .text.*) - } >rtc_iram_seg + } > rtc_iram_seg /* RTC slow memory holds RTC wake stub data/rodata, including from any source file @@ -35,6 +35,20 @@ SECTIONS _rtc_bss_end = ABSOLUTE(.); } > rtc_slow_seg + /* This section holds data that should not be initialized at power up + and will be retained during deep sleep. The section located in + RTC SLOW Memory area. User data marked with RTC_NOINIT_ATTR will be placed + into this section. See the file "esp_attr.h" for more information. + */ + .rtc_noinit (NOLOAD): + { + . = ALIGN(4); + _rtc_noinit_start = ABSOLUTE(.); + *(.rtc_noinit .rtc_noinit.*) + . = ALIGN(4) ; + _rtc_noinit_end = ABSOLUTE(.); + } > rtc_slow_seg + /* Send .iram0 code to iram */ .iram0.vectors : { @@ -99,7 +113,7 @@ SECTIONS *py/scheduler.o*(.literal .text .literal.* .text.*) _iram_text_end = ABSOLUTE(.); } > iram0_0_seg - + .dram0.data : { _data_start = ABSOLUTE(.); @@ -125,7 +139,21 @@ SECTIONS INCLUDE esp32.spiram.rom-functions-dram.ld _data_end = ABSOLUTE(.); . = ALIGN(4); - } >dram0_0_seg + } > dram0_0_seg + + /*This section holds data that should not be initialized at power up. + The section located in Internal SRAM memory region. The macro _NOINIT + can be used as attribute to place data into this section. + See the esp_attr.h file for more information. + */ + .noinit (NOLOAD): + { + . = ALIGN(4); + _noinit_start = ABSOLUTE(.); + *(.noinit .noinit.*) + . = ALIGN(4) ; + _noinit_end = ABSOLUTE(.); + } > dram0_0_seg /* Shared RAM */ .dram0.bss (NOLOAD) : @@ -148,8 +176,9 @@ SECTIONS *(COMMON) . = ALIGN (8); _bss_end = ABSOLUTE(.); + /* The heap starts right after end of this section */ _heap_start = ABSOLUTE(.); - } >dram0_0_seg + } > dram0_0_seg .flash.rodata : { From 34b2f6b6fc817e2ea0e253eedbee080895b89deb Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 15 Jun 2018 16:39:49 +1000 Subject: [PATCH 797/828] esp32/modules: Include umqtt library in frozen modules. --- ports/esp32/modules/umqtt/robust.py | 1 + ports/esp32/modules/umqtt/simple.py | 1 + 2 files changed, 2 insertions(+) create mode 120000 ports/esp32/modules/umqtt/robust.py create mode 120000 ports/esp32/modules/umqtt/simple.py diff --git a/ports/esp32/modules/umqtt/robust.py b/ports/esp32/modules/umqtt/robust.py new file mode 120000 index 0000000000..6bfbbcf552 --- /dev/null +++ b/ports/esp32/modules/umqtt/robust.py @@ -0,0 +1 @@ +../../../../../micropython-lib/umqtt.robust/umqtt/robust.py \ No newline at end of file diff --git a/ports/esp32/modules/umqtt/simple.py b/ports/esp32/modules/umqtt/simple.py new file mode 120000 index 0000000000..6419a46647 --- /dev/null +++ b/ports/esp32/modules/umqtt/simple.py @@ -0,0 +1 @@ +../../../../../micropython-lib/umqtt.simple/umqtt/simple.py \ No newline at end of file From 8b8c083625b15ae9e3560b96ee98408c4810544d Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 15 Jun 2018 18:01:36 +1000 Subject: [PATCH 798/828] drivers/sdcard: Change driver to use new block-device protocol. --- drivers/sdcard/sdcard.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/sdcard/sdcard.py b/drivers/sdcard/sdcard.py index 8f28b476e2..89d5d13ab4 100644 --- a/drivers/sdcard/sdcard.py +++ b/drivers/sdcard/sdcard.py @@ -223,9 +223,6 @@ class SDCard: self.cs(1) self.spi.write(b'\xff') - def count(self): - return self.sectors - def readblocks(self, block_num, buf): nblocks = len(buf) // 512 assert nblocks and not len(buf) % 512, 'Buffer length is invalid' @@ -270,3 +267,8 @@ class SDCard: offset += 512 nblocks -= 1 self.write_token(_TOKEN_STOP_TRAN) + + def ioctl(self, op, arg): + print('ioctl', op, arg) + if op == 4: # get number of blocks + return self.sectors From 1747d15c3afa12672d156664eabb29e3ba3b17d7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 15 Jun 2018 18:02:40 +1000 Subject: [PATCH 799/828] drivers/sdcard: Fix bug in computing number of sectors on SD Card. This was a typo from the very first commit of this file. --- drivers/sdcard/sdcard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sdcard/sdcard.py b/drivers/sdcard/sdcard.py index 89d5d13ab4..fe402f7457 100644 --- a/drivers/sdcard/sdcard.py +++ b/drivers/sdcard/sdcard.py @@ -97,7 +97,7 @@ class SDCard: csd = bytearray(16) self.readinto(csd) if csd[0] & 0xc0 == 0x40: # CSD version 2.0 - self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 2014 + self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024 elif csd[0] & 0xc0 == 0x00: # CSD version 1.0 (old, <=2GB) c_size = csd[6] & 0b11 | csd[7] << 2 | (csd[8] & 0b11000000) << 4 c_size_mult = ((csd[9] & 0b11) << 1) | csd[10] >> 7 From 564abb01a5526bd2d981791401e28774c7dcfe4c Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 16 Jun 2018 18:21:42 +1000 Subject: [PATCH 800/828] extmod/vfs_fat_diskio: Factor disk ioctl code to reduce code size. Functionality is unchanged. --- extmod/vfs_fat_diskio.c | 192 ++++++++++++++-------------------------- 1 file changed, 68 insertions(+), 124 deletions(-) diff --git a/extmod/vfs_fat_diskio.c b/extmod/vfs_fat_diskio.c index 712038f3e9..fa013d2786 100644 --- a/extmod/vfs_fat_diskio.c +++ b/extmod/vfs_fat_diskio.c @@ -53,59 +53,6 @@ STATIC fs_user_mount_t *disk_get_device(void *bdev) { return (fs_user_mount_t*)bdev; } -/*-----------------------------------------------------------------------*/ -/* Initialize a Drive */ -/*-----------------------------------------------------------------------*/ - -STATIC -DSTATUS disk_initialize ( - bdev_t pdrv /* Physical drive nmuber (0..) */ -) -{ - fs_user_mount_t *vfs = disk_get_device(pdrv); - if (vfs == NULL) { - return STA_NOINIT; - } - - if (vfs->flags & FSUSER_HAVE_IOCTL) { - // new protocol with ioctl; call ioctl(INIT, 0) - vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_INIT); - vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused - mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl); - if (ret != mp_const_none && MP_OBJ_SMALL_INT_VALUE(ret) != 0) { - // error initialising - return STA_NOINIT; - } - } - - if (vfs->writeblocks[0] == MP_OBJ_NULL) { - return STA_PROTECT; - } else { - return 0; - } -} - -/*-----------------------------------------------------------------------*/ -/* Get Disk Status */ -/*-----------------------------------------------------------------------*/ - -STATIC -DSTATUS disk_status ( - bdev_t pdrv /* Physical drive nmuber (0..) */ -) -{ - fs_user_mount_t *vfs = disk_get_device(pdrv); - if (vfs == NULL) { - return STA_NOINIT; - } - - if (vfs->writeblocks[0] == MP_OBJ_NULL) { - return STA_PROTECT; - } else { - return 0; - } -} - /*-----------------------------------------------------------------------*/ /* Read Sector(s) */ /*-----------------------------------------------------------------------*/ @@ -191,54 +138,21 @@ DRESULT disk_ioctl ( return RES_PARERR; } + // First part: call the relevant method of the underlying block device + mp_obj_t ret = mp_const_none; if (vfs->flags & FSUSER_HAVE_IOCTL) { // new protocol with ioctl - switch (cmd) { - case CTRL_SYNC: - vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_SYNC); - vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused - mp_call_method_n_kw(2, 0, vfs->u.ioctl); - return RES_OK; - - case GET_SECTOR_COUNT: { - vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_SEC_COUNT); - vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused - mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl); - *((DWORD*)buff) = mp_obj_get_int(ret); - return RES_OK; - } - - case GET_SECTOR_SIZE: { - vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_SEC_SIZE); - vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused - mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl); - if (ret == mp_const_none) { - // Default sector size - *((WORD*)buff) = 512; - } else { - *((WORD*)buff) = mp_obj_get_int(ret); - } - #if _MAX_SS != _MIN_SS - // need to store ssize because we use it in disk_read/disk_write - vfs->fatfs.ssize = *((WORD*)buff); - #endif - return RES_OK; - } - - case GET_BLOCK_SIZE: - *((DWORD*)buff) = 1; // erase block size in units of sector size - return RES_OK; - - case IOCTL_INIT: - *((DSTATUS*)buff) = disk_initialize(pdrv); - return RES_OK; - - case IOCTL_STATUS: - *((DSTATUS*)buff) = disk_status(pdrv); - return RES_OK; - - default: - return RES_PARERR; + static const uint8_t op_map[8] = { + [CTRL_SYNC] = BP_IOCTL_SYNC, + [GET_SECTOR_COUNT] = BP_IOCTL_SEC_COUNT, + [GET_SECTOR_SIZE] = BP_IOCTL_SEC_SIZE, + [IOCTL_INIT] = BP_IOCTL_INIT, + }; + uint8_t bp_op = op_map[cmd & 7]; + if (bp_op != 0) { + vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(bp_op); + vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused + ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl); } } else { // old protocol with sync and count @@ -247,38 +161,68 @@ DRESULT disk_ioctl ( if (vfs->u.old.sync[0] != MP_OBJ_NULL) { mp_call_method_n_kw(0, 0, vfs->u.old.sync); } - return RES_OK; + break; - case GET_SECTOR_COUNT: { - mp_obj_t ret = mp_call_method_n_kw(0, 0, vfs->u.old.count); - *((DWORD*)buff) = mp_obj_get_int(ret); - return RES_OK; - } + case GET_SECTOR_COUNT: + ret = mp_call_method_n_kw(0, 0, vfs->u.old.count); + break; case GET_SECTOR_SIZE: - *((WORD*)buff) = 512; // old protocol had fixed sector size - #if _MAX_SS != _MIN_SS - // need to store ssize because we use it in disk_read/disk_write - vfs->fatfs.ssize = 512; - #endif - return RES_OK; - - case GET_BLOCK_SIZE: - *((DWORD*)buff) = 1; // erase block size in units of sector size - return RES_OK; + // old protocol has fixed sector size of 512 bytes + break; case IOCTL_INIT: - *((DSTATUS*)buff) = disk_initialize(pdrv); - return RES_OK; - - case IOCTL_STATUS: - *((DSTATUS*)buff) = disk_status(pdrv); - return RES_OK; - - default: - return RES_PARERR; + // old protocol doesn't have init + break; } } + + // Second part: convert the result for return + switch (cmd) { + case CTRL_SYNC: + return RES_OK; + + case GET_SECTOR_COUNT: { + *((DWORD*)buff) = mp_obj_get_int(ret); + return RES_OK; + } + + case GET_SECTOR_SIZE: { + if (ret == mp_const_none) { + // Default sector size + *((WORD*)buff) = 512; + } else { + *((WORD*)buff) = mp_obj_get_int(ret); + } + #if _MAX_SS != _MIN_SS + // need to store ssize because we use it in disk_read/disk_write + vfs->fatfs.ssize = *((WORD*)buff); + #endif + return RES_OK; + } + + case GET_BLOCK_SIZE: + *((DWORD*)buff) = 1; // erase block size in units of sector size + return RES_OK; + + case IOCTL_INIT: + case IOCTL_STATUS: { + DSTATUS stat; + if (ret != mp_const_none && MP_OBJ_SMALL_INT_VALUE(ret) != 0) { + // error initialising + stat = STA_NOINIT; + } else if (vfs->writeblocks[0] == MP_OBJ_NULL) { + stat = STA_PROTECT; + } else { + stat = 0; + } + *((DSTATUS*)buff) = stat; + return RES_OK; + } + + default: + return RES_PARERR; + } } #endif // MICROPY_VFS && MICROPY_VFS_FAT From ceff433fccb3f12b9ae39a726e4893366481822a Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 18 Jun 2018 12:23:27 +1000 Subject: [PATCH 801/828] stm32/mboot: Adjust user-reset-mode timeout so it ends with mode=1. If the user button is held down indefinitely (eg unintenionally, or because the GPIO signal of the user button is connected to some external device) then it makes sense to end the reset mode cycle with the default mode of 1, which executes code as normal. --- ports/stm32/mboot/main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c index a87507fd50..92217a4bec 100644 --- a/ports/stm32/mboot/main.c +++ b/ports/stm32/mboot/main.c @@ -1011,11 +1011,12 @@ static int get_reset_mode(void) { int reset_mode = 1; if (usrbtn_state()) { // Cycle through reset modes while USR is held + // Timeout is roughly 20s, where reset_mode=1 systick_init(); led_init(); reset_mode = 0; - for (int i = 0; i < 1000; i++) { - if (i % 30 == 0) { + for (int i = 0; i < 1024; i++) { + if (i % 32 == 0) { if (++reset_mode > 4) { reset_mode = 1; } @@ -1027,7 +1028,7 @@ static int get_reset_mode(void) { if (!usrbtn_state()) { break; } - mp_hal_delay_ms(20); + mp_hal_delay_ms(19); } // Flash the selected reset mode for (int i = 0; i < 6; i++) { From 31cf49c672f6e141df2178e2ab0b6560244ea2e6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 18 Jun 2018 12:29:22 +1000 Subject: [PATCH 802/828] examples/embedding: Add code markup and fix typo in README.md. --- examples/embedding/README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/embedding/README.md b/examples/embedding/README.md index 804dfede6f..0dfc52e1dc 100644 --- a/examples/embedding/README.md +++ b/examples/embedding/README.md @@ -1,10 +1,10 @@ -Example of embedding MicroPython in a standlone C application -============================================================= +Example of embedding MicroPython in a standalone C application +============================================================== This directory contains a (very simple!) example of how to embed a MicroPython in an existing C application. -A C application is represented by the file hello-embed.c. It executes a simple +A C application is represented by the file `hello-embed.c`. It executes a simple Python statement which prints to the standard output. @@ -18,19 +18,19 @@ Building the example is as simple as running: It's worth to trace what's happening behind the scenes though: 1. As a first step, a MicroPython library is built. This is handled by a -separate makefile, Makefile.upylib. It is more or less complex, but the +separate makefile, `Makefile.upylib`. It is more or less complex, but the good news is that you won't need to change anything in it, just use it -as is, the main Makefile shows how. What may require editing though is +as is, the main `Makefile` shows how. What may require editing though is a MicroPython configuration file. MicroPython is highly configurable, so you would need to build a library suiting your application well, while -not bloating its size. Check the options in the file "mpconfigport.h". +not bloating its size. Check the options in the file `mpconfigport.h`. Included is a copy of the "minimal" Unix port, which should be a good start for minimal embedding. For the list of all available options, see -py/mpconfig.h. +`py/mpconfig.h`. 2. Once the MicroPython library is built, your application is compiled and linked it. The main Makefile is very simple and shows that the changes -you would need to do to your application's Makefile (or other build +you would need to do to your application's `Makefile` (or other build configuration) are also simple: a) You would need to use C99 standard (you're using this 15+ years old @@ -38,7 +38,7 @@ standard already, not a 25+ years old one, right?). b) You need to provide a path to MicroPython's top-level dir, for includes. -c) You need to include -DNO_QSTR compile-time flag. +c) You need to include `-DNO_QSTR` compile-time flag. d) Otherwise, just link with the MicroPython library produced in step 1. @@ -48,13 +48,13 @@ Out of tree build This example is set up to work out of the box, being part of the MicroPython tree. Your application of course will be outside of its tree, but the -only thing you need to do is to pass MPTOP variable pointing to +only thing you need to do is to pass `MPTOP` variable pointing to MicroPython directory to both Makefiles (in this example, the main Makefile -automatically passes it to Makefile.upylib; in your own Makefile, don't forget +automatically passes it to `Makefile.upylib`; in your own Makefile, don't forget to use a suitable value). A practical way to embed MicroPython in your application is to include it -as a git submodule. Suppose you included it as libs/micropython. Then in +as a git submodule. Suppose you included it as `libs/micropython`. Then in your main Makefile you would have something like: ~~~ From 6abede2ca9e221b6aefcaccbda0c89e367507df1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 13 Jun 2018 11:54:44 +1000 Subject: [PATCH 803/828] py/stream: Introduce and use efficient mp_get_stream to access stream_p. The existing mp_get_stream_raise() helper does explicit checks that the input object is a real pointer object, has a non-NULL stream protocol, and has the desired stream C method (read/write/ioctl). In most cases it is not necessary to do these checks because it is guaranteed that the input object has the stream protocol and desired C methods. For example, native objects that use the stream wrappers (eg mp_stream_readinto_obj) in their locals dict always have the stream protocol (or else they shouldn't have these wrappers in their locals dict). This patch introduces an efficient mp_get_stream() which doesn't do any checks and just extracts the stream protocol struct. This should be used in all cases where the argument object is known to be a stream. The existing mp_get_stream_raise() should be used primarily to verify that an object does have the correct stream protocol methods. All uses of mp_get_stream_raise() in py/stream.c have been converted to use mp_get_stream() because the argument is guaranteed to be a proper stream object. This patch improves efficiency of stream operations and reduces code size. --- py/stream.c | 25 ++++++++++--------------- py/stream.h | 5 +++++ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/py/stream.c b/py/stream.c index 393988d2c1..a65ba4c91b 100644 --- a/py/stream.c +++ b/py/stream.c @@ -1,3 +1,4 @@ + /* * This file is part of the MicroPython project, http://micropython.org/ * @@ -47,10 +48,9 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in); // be equal to input size). mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf_, mp_uint_t size, int *errcode, byte flags) { byte *buf = buf_; - mp_obj_base_t* s = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream); typedef mp_uint_t (*io_func_t)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode); io_func_t io_func; - const mp_stream_p_t *stream_p = s->type->protocol; + const mp_stream_p_t *stream_p = mp_get_stream(stream); if (flags & MP_STREAM_RW_WRITE) { io_func = (io_func_t)stream_p->write; } else { @@ -99,8 +99,6 @@ const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) { } STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte flags) { - const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_READ); - // What to do if sz < -1? Python docs don't specify this case. // CPython does a readall, but here we silently let negatives through, // and they will cause a MemoryError. @@ -109,6 +107,8 @@ STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte fl return stream_readall(args[0]); } + const mp_stream_p_t *stream_p = mp_get_stream(args[0]); + #if MICROPY_PY_BUILTINS_STR_UNICODE if (stream_p->is_text) { // We need to read sz number of unicode characters. Because we don't have any @@ -227,8 +227,6 @@ STATIC mp_obj_t stream_read1(size_t n_args, const mp_obj_t *args) { MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read1_obj, 1, 2, stream_read1); mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte flags) { - mp_get_stream_raise(self_in, MP_STREAM_OP_WRITE); - int error; mp_uint_t out_sz = mp_stream_rw(self_in, (void*)buf, len, &error, flags); if (error != 0) { @@ -276,7 +274,6 @@ STATIC mp_obj_t stream_write1_method(mp_obj_t self_in, mp_obj_t arg) { MP_DEFINE_CONST_FUN_OBJ_2(mp_stream_write1_obj, stream_write1_method); STATIC mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) { - mp_get_stream_raise(args[0], MP_STREAM_OP_READ); mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); @@ -305,7 +302,7 @@ STATIC mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) { MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto_obj, 2, 3, stream_readinto); STATIC mp_obj_t stream_readall(mp_obj_t self_in) { - const mp_stream_p_t *stream_p = mp_get_stream_raise(self_in, MP_STREAM_OP_READ); + const mp_stream_p_t *stream_p = mp_get_stream(self_in); mp_uint_t total_size = 0; vstr_t vstr; @@ -346,7 +343,7 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) { // Unbuffered, inefficient implementation of readline() for raw I/O files. STATIC mp_obj_t stream_unbuffered_readline(size_t n_args, const mp_obj_t *args) { - const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_READ); + const mp_stream_p_t *stream_p = mp_get_stream(args[0]); mp_int_t max_size = -1; if (n_args > 1) { @@ -421,7 +418,7 @@ mp_obj_t mp_stream_unbuffered_iter(mp_obj_t self) { } mp_obj_t mp_stream_close(mp_obj_t stream) { - const mp_stream_p_t *stream_p = mp_get_stream_raise(stream, MP_STREAM_OP_IOCTL); + const mp_stream_p_t *stream_p = mp_get_stream(stream); int error; mp_uint_t res = stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, &error); if (res == MP_STREAM_ERROR) { @@ -432,8 +429,6 @@ mp_obj_t mp_stream_close(mp_obj_t stream) { MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_close_obj, mp_stream_close); STATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args) { - const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_IOCTL); - struct mp_stream_seek_t seek_s; // TODO: Could be uint64 seek_s.offset = mp_obj_get_int(args[1]); @@ -447,6 +442,7 @@ STATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args) { mp_raise_OSError(MP_EINVAL); } + const mp_stream_p_t *stream_p = mp_get_stream(args[0]); int error; mp_uint_t res = stream_p->ioctl(args[0], MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &error); if (res == MP_STREAM_ERROR) { @@ -467,7 +463,7 @@ STATIC mp_obj_t stream_tell(mp_obj_t self) { MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_tell_obj, stream_tell); STATIC mp_obj_t stream_flush(mp_obj_t self) { - const mp_stream_p_t *stream_p = mp_get_stream_raise(self, MP_STREAM_OP_IOCTL); + const mp_stream_p_t *stream_p = mp_get_stream(self); int error; mp_uint_t res = stream_p->ioctl(self, MP_STREAM_FLUSH, 0, &error); if (res == MP_STREAM_ERROR) { @@ -478,8 +474,6 @@ STATIC mp_obj_t stream_flush(mp_obj_t self) { MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_flush_obj, stream_flush); STATIC mp_obj_t stream_ioctl(size_t n_args, const mp_obj_t *args) { - const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_IOCTL); - mp_buffer_info_t bufinfo; uintptr_t val = 0; if (n_args > 2) { @@ -490,6 +484,7 @@ STATIC mp_obj_t stream_ioctl(size_t n_args, const mp_obj_t *args) { } } + const mp_stream_p_t *stream_p = mp_get_stream(args[0]); int error; mp_uint_t res = stream_p->ioctl(args[0], mp_obj_get_int(args[1]), val, &error); if (res == MP_STREAM_ERROR) { diff --git a/py/stream.h b/py/stream.h index 3dec49a2e9..7b953138c3 100644 --- a/py/stream.h +++ b/py/stream.h @@ -90,6 +90,11 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_ioctl_obj); #define MP_STREAM_OP_WRITE (2) #define MP_STREAM_OP_IOCTL (4) +// Object is assumed to have a non-NULL stream protocol with valid r/w/ioctl methods +static inline const mp_stream_p_t *mp_get_stream(mp_const_obj_t self) { + return (const mp_stream_p_t*)((const mp_obj_base_t*)MP_OBJ_TO_PTR(self))->type->protocol; +} + const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags); mp_obj_t mp_stream_close(mp_obj_t stream); From e8398a58567cc94b866d46721fd06289601f5c8a Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 13 Jun 2018 12:37:49 +1000 Subject: [PATCH 804/828] extmod: Update to use new mp_get_stream helper. With this patch objects are only checked that they have the stream protocol at the start of their use as a stream, and afterwards the efficient mp_get_stream() helper is used to extract the stream protocol C methods. --- extmod/modujson.c | 4 +--- extmod/modussl_mbedtls.c | 7 +++++-- extmod/moduzlib.c | 3 ++- extmod/modwebrepl.c | 11 +++++------ extmod/modwebsocket.c | 3 ++- extmod/uos_dupterm.c | 3 ++- 6 files changed, 17 insertions(+), 14 deletions(-) diff --git a/extmod/modujson.c b/extmod/modujson.c index f731d71933..830b588fdc 100644 --- a/extmod/modujson.c +++ b/extmod/modujson.c @@ -35,9 +35,7 @@ #if MICROPY_PY_UJSON STATIC mp_obj_t mod_ujson_dump(mp_obj_t obj, mp_obj_t stream) { - if (!MP_OBJ_IS_OBJ(stream)) { - mp_raise_TypeError(NULL); - } + mp_get_stream_raise(stream, MP_STREAM_OP_WRITE); mp_print_t print = {MP_OBJ_TO_PTR(stream), mp_stream_write_adaptor}; mp_obj_print_helper(&print, obj, PRINT_JSON); return mp_const_none; diff --git a/extmod/modussl_mbedtls.c b/extmod/modussl_mbedtls.c index 1c9dfd17f9..08807d20ba 100644 --- a/extmod/modussl_mbedtls.c +++ b/extmod/modussl_mbedtls.c @@ -76,7 +76,7 @@ STATIC void mbedtls_debug(void *ctx, int level, const char *file, int line, cons STATIC int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) { mp_obj_t sock = *(mp_obj_t*)ctx; - const mp_stream_p_t *sock_stream = mp_get_stream_raise(sock, MP_STREAM_OP_WRITE); + const mp_stream_p_t *sock_stream = mp_get_stream(sock); int err; mp_uint_t out_sz = sock_stream->write(sock, buf, len, &err); @@ -93,7 +93,7 @@ STATIC int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) { STATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) { mp_obj_t sock = *(mp_obj_t*)ctx; - const mp_stream_p_t *sock_stream = mp_get_stream_raise(sock, MP_STREAM_OP_READ); + const mp_stream_p_t *sock_stream = mp_get_stream(sock); int err; mp_uint_t out_sz = sock_stream->read(sock, buf, len, &err); @@ -109,6 +109,9 @@ STATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) { STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { + // Verify the socket object has the full stream protocol + mp_get_stream_raise(sock, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); + #if MICROPY_PY_USSL_FINALISER mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t); #else diff --git a/extmod/moduzlib.c b/extmod/moduzlib.c index e9af07370e..940b72805d 100644 --- a/extmod/moduzlib.c +++ b/extmod/moduzlib.c @@ -53,7 +53,7 @@ STATIC unsigned char read_src_stream(TINF_DATA *data) { p -= offsetof(mp_obj_decompio_t, decomp); mp_obj_decompio_t *self = (mp_obj_decompio_t*)p; - const mp_stream_p_t *stream = mp_get_stream_raise(self->src_stream, MP_STREAM_OP_READ); + const mp_stream_p_t *stream = mp_get_stream(self->src_stream); int err; byte c; mp_uint_t out_sz = stream->read(self->src_stream, &c, 1, &err); @@ -68,6 +68,7 @@ STATIC unsigned char read_src_stream(TINF_DATA *data) { STATIC mp_obj_t decompio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 1, 2, false); + mp_get_stream_raise(args[0], MP_STREAM_OP_READ); mp_obj_decompio_t *o = m_new_obj(mp_obj_decompio_t); o->base.type = type; memset(&o->decomp, 0, sizeof(o->decomp)); diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c index 983b5a10ce..06da210d15 100644 --- a/extmod/modwebrepl.c +++ b/extmod/modwebrepl.c @@ -76,7 +76,7 @@ STATIC char denied_prompt[] = "\r\nAccess denied\r\n"; STATIC char webrepl_passwd[10]; STATIC void write_webrepl(mp_obj_t websock, const void *buf, size_t len) { - const mp_stream_p_t *sock_stream = mp_get_stream_raise(websock, MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); + const mp_stream_p_t *sock_stream = mp_get_stream(websock); int err; int old_opts = sock_stream->ioctl(websock, MP_STREAM_SET_DATA_OPTS, FRAME_BIN, &err); sock_stream->write(websock, buf, len, &err); @@ -86,7 +86,7 @@ STATIC void write_webrepl(mp_obj_t websock, const void *buf, size_t len) { #define SSTR(s) s, sizeof(s) - 1 STATIC void write_webrepl_str(mp_obj_t websock, const char *str, int sz) { int err; - const mp_stream_p_t *sock_stream = mp_get_stream_raise(websock, MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); + const mp_stream_p_t *sock_stream = mp_get_stream(websock); sock_stream->write(websock, str, sz, &err); } @@ -110,8 +110,7 @@ STATIC mp_obj_t webrepl_make_new(const mp_obj_type_t *type, size_t n_args, size_ } STATIC int write_file_chunk(mp_obj_webrepl_t *self) { - const mp_stream_p_t *file_stream = - mp_get_stream_raise(self->cur_file, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); + const mp_stream_p_t *file_stream = mp_get_stream(self->cur_file); byte readbuf[2 + 256]; int err; mp_uint_t out_sz = file_stream->read(self->cur_file, readbuf + 2, sizeof(readbuf) - 2, &err); @@ -181,7 +180,7 @@ STATIC mp_uint_t _webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int // We know that os.dupterm always calls with size = 1 assert(size == 1); mp_obj_webrepl_t *self = self_in; - const mp_stream_p_t *sock_stream = mp_get_stream_raise(self->sock, MP_STREAM_OP_READ); + const mp_stream_p_t *sock_stream = mp_get_stream(self->sock); mp_uint_t out_sz = sock_stream->read(self->sock, buf, size, errcode); //DEBUG_printf("webrepl: Read %d initial bytes from websocket\n", out_sz); if (out_sz == 0 || out_sz == MP_STREAM_ERROR) { @@ -293,7 +292,7 @@ STATIC mp_uint_t webrepl_write(mp_obj_t self_in, const void *buf, mp_uint_t size // Don't forward output until passwd is entered return size; } - const mp_stream_p_t *stream_p = mp_get_stream_raise(self->sock, MP_STREAM_OP_WRITE); + const mp_stream_p_t *stream_p = mp_get_stream(self->sock); return stream_p->write(self->sock, buf, size, errcode); } diff --git a/extmod/modwebsocket.c b/extmod/modwebsocket.c index 5a826ec64c..c556f2b770 100644 --- a/extmod/modwebsocket.c +++ b/extmod/modwebsocket.c @@ -59,6 +59,7 @@ STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t si STATIC mp_obj_t websocket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 1, 2, false); + mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); mp_obj_websocket_t *o = m_new_obj(mp_obj_websocket_t); o->base.type = type; o->sock = args[0]; @@ -75,7 +76,7 @@ STATIC mp_obj_t websocket_make_new(const mp_obj_type_t *type, size_t n_args, siz STATIC mp_uint_t websocket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in); - const mp_stream_p_t *stream_p = mp_get_stream_raise(self->sock, MP_STREAM_OP_READ); + const mp_stream_p_t *stream_p = mp_get_stream(self->sock); while (1) { if (self->to_recv != 0) { mp_uint_t out_sz = stream_p->read(self->sock, self->buf + self->buf_pos, self->to_recv, errcode); diff --git a/extmod/uos_dupterm.c b/extmod/uos_dupterm.c index 822d640379..cc6d97f419 100644 --- a/extmod/uos_dupterm.c +++ b/extmod/uos_dupterm.c @@ -62,7 +62,7 @@ int mp_uos_dupterm_rx_chr(void) { if (nlr_push(&nlr) == 0) { byte buf[1]; int errcode; - const mp_stream_p_t *stream_p = mp_get_stream_raise(MP_STATE_VM(dupterm_objs[idx]), MP_STREAM_OP_READ); + const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_VM(dupterm_objs[idx])); mp_uint_t out_sz = stream_p->read(MP_STATE_VM(dupterm_objs[idx]), buf, 1, &errcode); if (out_sz == 0) { nlr_pop(); @@ -125,6 +125,7 @@ STATIC mp_obj_t mp_uos_dupterm(size_t n_args, const mp_obj_t *args) { if (args[0] == mp_const_none) { MP_STATE_VM(dupterm_objs[idx]) = MP_OBJ_NULL; } else { + mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); MP_STATE_VM(dupterm_objs[idx]) = args[0]; } From a5f5552a0a52cfd37f1db4d6df2194a4090561f5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 13 Jun 2018 12:47:29 +1000 Subject: [PATCH 805/828] tests/unix/extra_coverage: Don't test stream objs with NULL write fun. This behaviour of a NULL write C method on a stream that uses the write adaptor objects is no longer supported. It was only ever used by the coverage build for testing the fail path of mp_get_stream_raise(). --- ports/unix/coverage.c | 1 - tests/unix/extra_coverage.py | 6 +----- tests/unix/extra_coverage.py.exp | 1 - 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index eba84f38b3..7820f6d736 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -118,7 +118,6 @@ STATIC mp_uint_t stest_read2(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc STATIC const mp_rom_map_elem_t rawfile_locals_dict_table2[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, }; STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict2, rawfile_locals_dict_table2); diff --git a/tests/unix/extra_coverage.py b/tests/unix/extra_coverage.py index 65011198dd..13721f1f47 100644 --- a/tests/unix/extra_coverage.py +++ b/tests/unix/extra_coverage.py @@ -38,11 +38,7 @@ except OSError: stream.set_error(0) print(stream.ioctl(0, bytearray(10))) # successful ioctl call -stream2 = data[3] # is textio and sets .write = NULL -try: - print(stream2.write(b'1')) # attempt to call NULL implementation -except OSError: - print('OSError') +stream2 = data[3] # is textio print(stream2.read(1)) # read 1 byte encounters non-blocking error with textio stream # test BufferedWriter with stream errors diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index 009874509d..9df8527577 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -90,7 +90,6 @@ b'123' b'123' OSError 0 -OSError None None frzstr1 From 0ecce77c663ee0ebb7fa6eefaf28094ee1dbf051 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 13 Jun 2018 12:53:25 +1000 Subject: [PATCH 806/828] tests/extmod/ujson_dump.py: Add test for dump to non-stream object. --- tests/extmod/ujson_dump.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/extmod/ujson_dump.py b/tests/extmod/ujson_dump.py index c80e533ed7..b1cb4a9cbc 100644 --- a/tests/extmod/ujson_dump.py +++ b/tests/extmod/ujson_dump.py @@ -16,3 +16,15 @@ print(s.getvalue()) s = StringIO() json.dump({"a": (2, [3, None])}, s) print(s.getvalue()) + +# dump to a small-int not allowed +try: + json.dump(123, 1) +except (AttributeError, OSError): # CPython and uPy have different errors + print('Exception') + +# dump to an object not allowed +try: + json.dump(123, {}) +except (AttributeError, OSError): # CPython and uPy have different errors + print('Exception') From 48829cd3c6e723eadf5eb60fd8e521a1761fe8b3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 13 Jun 2018 13:13:36 +1000 Subject: [PATCH 807/828] tests/extmod: Add test for ujson.dump writing to a user IOBase object. --- tests/extmod/ujson_dump_iobase.py | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tests/extmod/ujson_dump_iobase.py diff --git a/tests/extmod/ujson_dump_iobase.py b/tests/extmod/ujson_dump_iobase.py new file mode 100644 index 0000000000..d30d1b561e --- /dev/null +++ b/tests/extmod/ujson_dump_iobase.py @@ -0,0 +1,32 @@ +# test ujson.dump in combination with uio.IOBase + +try: + import uio as io + import ujson as json +except ImportError: + try: + import io, json + except ImportError: + print('SKIP') + raise SystemExit + +if not hasattr(io, 'IOBase'): + print('SKIP') + raise SystemExit + + +# a user stream that only has the write method +class S(io.IOBase): + def __init__(self): + self.buf = '' + def write(self, buf): + if type(buf) == bytearray: + # uPy passes a bytearray, CPython passes a str + buf = str(buf, 'ascii') + self.buf += buf + + +# dump to the user stream +s = S() +json.dump([123, {}], s) +print(s.buf) From 0d3de686692e25c85d322c626921bc982a79581d Mon Sep 17 00:00:00 2001 From: rolandvs Date: Wed, 13 Jun 2018 12:50:10 +0200 Subject: [PATCH 808/828] stm32/boards/stm32f091_af.csv: Split labels that are multiple funcs. --- ports/stm32/boards/stm32f091_af.csv | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ports/stm32/boards/stm32f091_af.csv b/ports/stm32/boards/stm32f091_af.csv index c1ff5aaf29..38e134f8a9 100644 --- a/ports/stm32/boards/stm32f091_af.csv +++ b/ports/stm32/boards/stm32f091_af.csv @@ -18,10 +18,10 @@ PortA,PA14,SWCLK,USART2_TX,,,,,,,,,,,,,,, PortA,PA15,SPI1_NSS/I2S1_WS,USART2_RX,TIM2_CH1_ETR,EVENTOUT,USART4_RTS,,,,,,,,,,,, PortB,PB0,EVENTOUT,TIM3_CH3,TIM1_CH2N,TSC_G3_IO2,USART3_CK,,,,,,,,,,,,ADC1_IN8 PortB,PB1,TIM14_CH1,TIM3_CH4,TIM1_CH3N,TSC_G3_IO3,USART3_RTS,,,,,,,,,,,,ADC1_IN9 -PortB,PB2,,,,TSC_G3_IO4,,,,,,,,,,, +PortB,PB2,,,,TSC_G3_IO4,,,,,,,,,,,,, PortB,PB3,SPI1_SCK/I2S1_CK,EVENTOUT,TIM2_CH2,TSC_G5_IO1,USART5_TX,,,,,,,,,, PortB,PB4,SPI1_MISO/I2S1_MCK,TIM3_CH1,EVENTOUT,TSC_G5_IO2,USART5_RX,TIM17_BKIN,,,,,,,,, -PortB,PB5,SPI1_MOSI/I2S1_SD,TIM3_CH2,TIM16_BKIN,I2C1_SMBA,USART5_CK_RTS,,,,,,,,,, +PortB,PB5,SPI1_MOSI/I2S1_SD,TIM3_CH2,TIM16_BKIN,I2C1_SMBA,USART5_CK/USART5_RTS,,,,,,,,,, PortB,PB6,USART1_TX,I2C1_SCL,TIM16_CH1N,TSC_G5_IO3,,,,,,,,,,, PortB,PB7,USART1_RX,I2C1_SDA,TIM17_CH1N,TSC_G5_IO4,USART4_CTS,,,,,,,,,, PortB,PB8,CEC,I2C1_SCL,TIM16_CH1,TSC_SYNC,CAN1_RX,,,,,,,,,, @@ -60,10 +60,10 @@ PortD,PD8,USART3_TX,,,,,,,,,,,,,,,, PortD,PD9,USART3_RX,,,,,,,,,,,,,,,, PortD,PD10,USART3_CK,,,,,,,,,,,,,,,, PortD,PD11,USART3_CTS,,,,,,,,,,,,,,,, -PortD,PD12,USART3_RTS,TSC_G8_IO1,USART8_CK_RTS,,,,,,,,,,,,,, +PortD,PD12,USART3_RTS,TSC_G8_IO1,USART8_CK/USART8_RTS,,,,,,,,,,,,,, PortD,PD13,USART8_TX,TSC_G8_IO2,,,,,,,,,,,,,,, PortD,PD14,USART8_RX,TSC_G8_IO3,,,,,,,,,,,,,,, -PortD,PD15,CRS_SYNC,TSC_G8_IO4,USART7_CK_RTS,,,,,,,,,,,,,, +PortD,PD15,CRS_SYNC,TSC_G8_IO4,USART7_CK/USART7_RTS,,,,,,,,,,,,,, PortE,PE0,TIM16_CH1,EVENTOUT,,,,,,,,,,,,,,, PortE,PE1,TIM17_CH1,EVENTOUT,,,,,,,,,,,,,,, PortE,PE2,TIM3_ETR,TSC_G7_IO1,,,,,,,,,,,,,,, @@ -71,7 +71,7 @@ PortE,PE3,TIM3_CH1,TSC_G7_IO2,,,,,,,,,,,,,,, PortE,PE4,TIM3_CH2,TSC_G7_IO3,,,,,,,,,,,,,,, PortE,PE5,TIM3_CH3,TSC_G7_IO4,,,,,,,,,,,,,,, PortE,PE6,TIM3_CH4,,,,,,,,,,,,,,,, -PortE,PE7,TIM1_ETR,USART5_CK_RTS,,,,,,,,,,,,,,, +PortE,PE7,TIM1_ETR,USART5_CK/USART5_RTS,,,,,,,,,,,,,,, PortE,PE8,TIM1_CH1N,USART4_TX,,,,,,,,,,,,,,, PortE,PE9,TIM1_CH1,USART4_RX,,,,,,,,,,,,,,, PortE,PE10,TIM1_CH2N,USART5_TX,,,,,,,,,,,,,,, @@ -82,8 +82,8 @@ PortE,PE14,TIM1_CH4,SPI1_MISO/I2S1_MCK,,,,,,,,,,,,,,, PortE,PE15,TIM1_BKIN,SPI1_MOSI/I2S1_SD,,,,,,,,,,,,,,, PortF,PF0,CRS_SYNC,I2C1_SDA,,,,,,,,,,,,,,, PortF,PF1,,I2C1_SCL,,,,,,,,,,,,,,, -PortF,PF2,EVENTOUT,USART7_TX,USART7_CK_RTS,,,,,,,,,,,,,, -PortF,PF3,EVENTOUT,USART7_RX,USART6_CK_RTS,,,,,,,,,,,,,, +PortF,PF2,EVENTOUT,USART7_TX,USART7_CK/USART7_RTS,,,,,,,,,,,,,, +PortF,PF3,EVENTOUT,USART7_RX,USART6_CK/USART6_RTS,,,,,,,,,,,,,, PortF,PF6,,,,,,,,,,,,,,,,, PortF,PF9,TIM15_CH1,USART6_TX,,,,,,,,,,,,,,, PortF,PF10,TIM15_CH2,USART6_RX,,,,,,,,,,,,,,, From ca2b1d6b36b11706b537eba90144469ba28561d2 Mon Sep 17 00:00:00 2001 From: rolandvs Date: Wed, 13 Jun 2018 20:03:12 +0200 Subject: [PATCH 809/828] stm32/boards/NUCLEO_F091RC: Add Arduino-named pins and rename CPU pins. To match pin labels on other NUCLEO 64 boards. --- ports/stm32/boards/NUCLEO_F091RC/pins.csv | 129 ++++++++++++++-------- 1 file changed, 83 insertions(+), 46 deletions(-) diff --git a/ports/stm32/boards/NUCLEO_F091RC/pins.csv b/ports/stm32/boards/NUCLEO_F091RC/pins.csv index 33f9628bb4..36d3141083 100644 --- a/ports/stm32/boards/NUCLEO_F091RC/pins.csv +++ b/ports/stm32/boards/NUCLEO_F091RC/pins.csv @@ -1,50 +1,87 @@ +D0,PA3 +D1,PA2 +D2,PA10 +D3,PB3 +D4,PB5 +D5,PB4 +D6,PB10 +D7,PA8 +D8,PA9 +D9,PC7 +D10,PB6 +D11,PA7 +D12,PA6 +D13,PA5 +D14,PB9 +D15,PB8 A0,PA0 A1,PA1 -A2,PA2 -A3,PA3 -A4,PA4 -A5,PA5 -A6,PA6 -A7,PA7 -A8,PA8 -A9,PA9 -A10,PA10 -A11,PA11 -A12,PA12 -A13,PA13 -A14,PA14 -A15,PA15 -B0,PB0 -B1,PB1 -B2,PB2 -B3,PB3 -B4,PB4 -B5,PB5 -B6,PB6 -B7,PB7 -B8,PB8 -B9,PB9 -B10,PB10 -B11,PB11 -B12,PB12 -B13,PB13 -B14,PB14 -B15,PB15 -C0,PC0 -C1,PC1 -C2,PC2 -C3,PC3 -C4,PC4 -C5,PC5 -C6,PC6 -C7,PC7 -C8,PC8 -C9,PC9 -C10,PC10 -C11,PC11 -C12,PC12 -C13,PC13 -C14,PC14 -C15,PC15 +A2,PA4 +A3,PB0 +A4,PC1 +A5,PC0 +RX,PA3 +TX,PA2 +SCL,PB8 +SDA,PB9 +SCK,PA5 +MISO,PA6 +MOSI,PA7 +CS,PB6 +BOOT0,PF11 +SWDIO,PA13 +SWCLK,PA14 USER_B1,PC13 LED_GREEN,PA5 +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA11,PA11 +PA12,PA12 +PA13,PA13 +PA14,PA14 +PA15,PA15 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PB3,PB3 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PB10,PB10 +PB11,PB11 +PB12,PB12 +PB13,PB13 +PB14,PB14 +PB15,PB15 +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PC4,PC4 +PC5,PC5 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PC13,PC13 +PC14,PC14 +PC15,PC15 +PD2,PD2 +PF0,PF0 +PF1,PF1 +PF11,PF11 From c00ee200accb0f79fc2a7829ebe4567258ed40c0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 18 Jun 2018 13:40:53 +1000 Subject: [PATCH 810/828] py/objarray: Replace 0x80 with new MP_OBJ_ARRAY_TYPECODE_FLAG_RW macro. --- py/objarray.c | 8 ++++---- py/objarray.h | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/py/objarray.c b/py/objarray.c index a35539484b..aa9fa3b737 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -222,7 +222,7 @@ STATIC mp_obj_t memoryview_make_new(const mp_obj_type_t *type_in, size_t n_args, // test if the object can be written to if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_RW)) { - self->typecode |= 0x80; // used to indicate writable buffer + self->typecode |= MP_OBJ_ARRAY_TYPECODE_FLAG_RW; // indicate writable buffer } return MP_OBJ_FROM_PTR(self); @@ -414,7 +414,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value uint8_t* dest_items = o->items; #if MICROPY_PY_BUILTINS_MEMORYVIEW if (o->base.type == &mp_type_memoryview) { - if ((o->typecode & 0x80) == 0) { + if (!(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) { // store to read-only memoryview not allowed return MP_OBJ_NULL; } @@ -471,7 +471,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value #if MICROPY_PY_BUILTINS_MEMORYVIEW if (o->base.type == &mp_type_memoryview) { index += o->free; - if (value != MP_OBJ_SENTINEL && (o->typecode & 0x80) == 0) { + if (value != MP_OBJ_SENTINEL && !(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) { // store to read-only memoryview return MP_OBJ_NULL; } @@ -497,7 +497,7 @@ STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_ui bufinfo->typecode = o->typecode & TYPECODE_MASK; #if MICROPY_PY_BUILTINS_MEMORYVIEW if (o->base.type == &mp_type_memoryview) { - if ((o->typecode & 0x80) == 0 && (flags & MP_BUFFER_WRITE)) { + if (!(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW) && (flags & MP_BUFFER_WRITE)) { // read-only memoryview return 1; } diff --git a/py/objarray.h b/py/objarray.h index 0389668458..0dad705711 100644 --- a/py/objarray.h +++ b/py/objarray.h @@ -29,6 +29,9 @@ #include "py/obj.h" +// Used only for memoryview types, set in "typecode" to indicate a writable memoryview +#define MP_OBJ_ARRAY_TYPECODE_FLAG_RW (0x80) + typedef struct _mp_obj_array_t { mp_obj_base_t base; size_t typecode : 8; From 338af99a7f3b8f2231be7475500a2bbf6a2bd723 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 18 Jun 2018 13:42:05 +1000 Subject: [PATCH 811/828] stm32/can: Use MP_OBJ_ARRAY_TYPECODE_FLAG_RW where appropriate. --- ports/stm32/can.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/stm32/can.c b/ports/stm32/can.c index 22ac5509c2..7680b0de42 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -723,8 +723,8 @@ STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t * mp_raise_TypeError(NULL); } mp_obj_array_t *mv = MP_OBJ_TO_PTR(items[3]); - if (!(mv->typecode == (0x80 | BYTEARRAY_TYPECODE) - || (mv->typecode | 0x20) == (0x80 | 'b'))) { + if (!(mv->typecode == (MP_OBJ_ARRAY_TYPECODE_FLAG_RW | BYTEARRAY_TYPECODE) + || (mv->typecode | 0x20) == (MP_OBJ_ARRAY_TYPECODE_FLAG_RW | 'b'))) { mp_raise_ValueError(NULL); } mv->len = rx_msg.DLC; From e49cd106b4bbbb47b782f73b66000df6094f7afe Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 18 Jun 2018 17:36:52 +1000 Subject: [PATCH 812/828] stm32/spi: Fix SPI driver so it can send/recv more than 65535 bytes. The DMA peripheral is limited to transferring 65535 elements at a time so in order to send more than that the SPI driver must split the transfers up. The user must be aware of this limit if they are relying on precise timing of the entire SPI transfer, because there might be a small delay between the split transfers. Fixes issue #3851, and thanks to @kwagyeman for the original fix. --- ports/stm32/spi.c | 62 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c index c578ac7da2..e8621b0ab3 100644 --- a/ports/stm32/spi.c +++ b/ports/stm32/spi.c @@ -401,8 +401,7 @@ void spi_deinit(const spi_t *spi_obj) { } } -STATIC HAL_StatusTypeDef spi_wait_dma_finished(const spi_t *spi, uint32_t timeout) { - uint32_t start = HAL_GetTick(); +STATIC HAL_StatusTypeDef spi_wait_dma_finished(const spi_t *spi, uint32_t t_start, uint32_t timeout) { volatile HAL_SPI_StateTypeDef *state = &spi->spi->State; for (;;) { // Do an atomic check of the state; WFI will exit even if IRQs are disabled @@ -413,7 +412,7 @@ STATIC HAL_StatusTypeDef spi_wait_dma_finished(const spi_t *spi, uint32_t timeou } __WFI(); enable_irq(irq_state); - if (HAL_GetTick() - start >= timeout) { + if (HAL_GetTick() - t_start >= timeout) { return HAL_TIMEOUT; } } @@ -430,6 +429,8 @@ STATIC void spi_transfer(const spi_t *self, size_t len, const uint8_t *src, uint // time directly after the SPI/DMA is initialised. The cause of this is // unknown but we sidestep the issue by using polling for 1 byte transfer. + // Note: DMA transfers are limited to 65535 bytes at a time. + HAL_StatusTypeDef status; if (dest == NULL) { @@ -442,10 +443,20 @@ STATIC void spi_transfer(const spi_t *self, size_t len, const uint8_t *src, uint self->spi->hdmatx = &tx_dma; self->spi->hdmarx = NULL; MP_HAL_CLEAN_DCACHE(src, len); - status = HAL_SPI_Transmit_DMA(self->spi, (uint8_t*)src, len); - if (status == HAL_OK) { - status = spi_wait_dma_finished(self, timeout); - } + uint32_t t_start = HAL_GetTick(); + do { + uint32_t l = MIN(len, 65535); + status = HAL_SPI_Transmit_DMA(self->spi, (uint8_t*)src, l); + if (status != HAL_OK) { + break; + } + status = spi_wait_dma_finished(self, t_start, timeout); + if (status != HAL_OK) { + break; + } + len -= l; + src += l; + } while (len); dma_deinit(self->tx_dma_descr); } } else if (src == NULL) { @@ -464,10 +475,20 @@ STATIC void spi_transfer(const spi_t *self, size_t len, const uint8_t *src, uint dma_init(&rx_dma, self->rx_dma_descr, self->spi); self->spi->hdmarx = &rx_dma; MP_HAL_CLEANINVALIDATE_DCACHE(dest, len); - status = HAL_SPI_Receive_DMA(self->spi, dest, len); - if (status == HAL_OK) { - status = spi_wait_dma_finished(self, timeout); - } + uint32_t t_start = HAL_GetTick(); + do { + uint32_t l = MIN(len, 65535); + status = HAL_SPI_Receive_DMA(self->spi, dest, l); + if (status != HAL_OK) { + break; + } + status = spi_wait_dma_finished(self, t_start, timeout); + if (status != HAL_OK) { + break; + } + len -= l; + dest += l; + } while (len); if (self->spi->hdmatx != NULL) { dma_deinit(self->tx_dma_descr); } @@ -485,10 +506,21 @@ STATIC void spi_transfer(const spi_t *self, size_t len, const uint8_t *src, uint self->spi->hdmarx = &rx_dma; MP_HAL_CLEAN_DCACHE(src, len); MP_HAL_CLEANINVALIDATE_DCACHE(dest, len); - status = HAL_SPI_TransmitReceive_DMA(self->spi, (uint8_t*)src, dest, len); - if (status == HAL_OK) { - status = spi_wait_dma_finished(self, timeout); - } + uint32_t t_start = HAL_GetTick(); + do { + uint32_t l = MIN(len, 65535); + status = HAL_SPI_TransmitReceive_DMA(self->spi, (uint8_t*)src, dest, l); + if (status != HAL_OK) { + break; + } + status = spi_wait_dma_finished(self, t_start, timeout); + if (status != HAL_OK) { + break; + } + len -= l; + src += l; + dest += l; + } while (len); dma_deinit(self->tx_dma_descr); dma_deinit(self->rx_dma_descr); } From 6d8816fe84f3e9de55b544aec71bb1ebc204d745 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 18 Jun 2018 17:50:34 +1000 Subject: [PATCH 813/828] tests/import: Add test for importing invalid .mpy file. --- tests/import/mpy_invalid.py | 67 +++++++++++++++++++++++++++++++++ tests/import/mpy_invalid.py.exp | 3 ++ 2 files changed, 70 insertions(+) create mode 100644 tests/import/mpy_invalid.py create mode 100644 tests/import/mpy_invalid.py.exp diff --git a/tests/import/mpy_invalid.py b/tests/import/mpy_invalid.py new file mode 100644 index 0000000000..6a4e116e78 --- /dev/null +++ b/tests/import/mpy_invalid.py @@ -0,0 +1,67 @@ +# test importing of invalid .mpy files + +import sys, uio + +try: + uio.IOBase + import uos + uos.mount +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + + +class UserFile(uio.IOBase): + def __init__(self, data): + self.data = data + self.pos = 0 + def read(self): + return self.data + def readinto(self, buf): + n = 0 + while n < len(buf) and self.pos < len(self.data): + buf[n] = self.data[self.pos] + n += 1 + self.pos += 1 + return n + def ioctl(self, req, arg): + return 0 + + +class UserFS: + def __init__(self, files): + self.files = files + def mount(self, readonly, mksfs): + pass + def umount(self): + pass + def stat(self, path): + if path in self.files: + return (32768, 0, 0, 0, 0, 0, 0, 0, 0, 0) + raise OSError + def open(self, path, mode): + return UserFile(self.files[path]) + + +# these are the test .mpy files +user_files = { + '/mod0.mpy': b'', # empty file + '/mod1.mpy': b'M', # too short header + '/mod2.mpy': b'M\x00\x00\x00', # bad version +} + +# create and mount a user filesystem +uos.mount(UserFS(user_files), '/userfs') +sys.path.append('/userfs') + +# import .mpy files from the user filesystem +for i in range(len(user_files)): + mod = 'mod%u' % i + try: + __import__(mod) + except ValueError as er: + print(mod, 'ValueError', er) + +# unmount and undo path addition +uos.umount('/userfs') +sys.path.pop() diff --git a/tests/import/mpy_invalid.py.exp b/tests/import/mpy_invalid.py.exp new file mode 100644 index 0000000000..1727ea1cea --- /dev/null +++ b/tests/import/mpy_invalid.py.exp @@ -0,0 +1,3 @@ +mod0 ValueError incompatible .mpy file +mod1 ValueError incompatible .mpy file +mod2 ValueError incompatible .mpy file From 5962c210c59c21cd1641bac9d7a84c3a4a8b0cf6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Jun 2018 23:23:17 +1000 Subject: [PATCH 814/828] stm32/mboot: Define constants for reset mode cycling and timeout. And fix timeout value so that it does actually finish with reset_mode=1. --- ports/stm32/mboot/main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c index 92217a4bec..5e2e1819f6 100644 --- a/ports/stm32/mboot/main.c +++ b/ports/stm32/mboot/main.c @@ -1004,6 +1004,8 @@ static int pyb_usbdd_shutdown(void) { /******************************************************************************/ // main +#define RESET_MODE_NUM_STATES (4) +#define RESET_MODE_TIMEOUT_CYCLES (8) #define RESET_MODE_LED_STATES 0x7421 static int get_reset_mode(void) { @@ -1015,9 +1017,9 @@ static int get_reset_mode(void) { systick_init(); led_init(); reset_mode = 0; - for (int i = 0; i < 1024; i++) { + for (int i = 0; i < (RESET_MODE_NUM_STATES * RESET_MODE_TIMEOUT_CYCLES + 1) * 32; i++) { if (i % 32 == 0) { - if (++reset_mode > 4) { + if (++reset_mode > RESET_MODE_NUM_STATES) { reset_mode = 1; } uint8_t l = RESET_MODE_LED_STATES >> ((reset_mode - 1) * 4); From 561ae9a91bebac3184596cefc85f5cea82974aae Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 20 Jun 2018 12:23:46 +1000 Subject: [PATCH 815/828] stm32/boards/NUCLEO_F091RC: Fix TICK_INT_PRIORITY so it is highest prio. Fixes issue #3880. --- ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h index 4e4ab9dbfa..53ea047cbd 100644 --- a/ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h @@ -162,9 +162,7 @@ * @brief This is the HAL system configuration section */ #define VDD_VALUE 3300U /*!< Value of VDD in mv */ -#define TICK_INT_PRIORITY ((uint32_t)(1U<<__NVIC_PRIO_BITS) - 1U) /*!< tick interrupt priority (lowest by default) */ - /* Warning: Must be set to higher priority for HAL_Delay() */ - /* and HAL_GetTick() usage under interrupt context */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ #define USE_RTOS 0U #define PREFETCH_ENABLE 1U #define INSTRUCTION_CACHE_ENABLE 0U From 2c8d130f702d07041e30d808b974b0ba2a1e51e0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 20 Jun 2018 15:56:32 +1000 Subject: [PATCH 816/828] py/stream: Update comment for mp_stream_write_adaptor. --- py/stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/stream.c b/py/stream.c index a65ba4c91b..b9932b35e8 100644 --- a/py/stream.c +++ b/py/stream.c @@ -242,7 +242,7 @@ mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte fla } } -// XXX hack +// This is used to adapt a stream object to an mp_print_t interface void mp_stream_write_adaptor(void *self, const char *buf, size_t len) { mp_stream_write(MP_OBJ_FROM_PTR(self), buf, len, MP_STREAM_RW_WRITE); } From 582b190764641e5049768da1ba8962c841ec014b Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 20 Jun 2018 15:57:10 +1000 Subject: [PATCH 817/828] py: Add checks for stream objects in print() and sys.print_exception(). --- py/modbuiltins.c | 2 +- py/modsys.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/py/modbuiltins.c b/py/modbuiltins.c index b216e021f3..c169b2ee49 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -386,7 +386,7 @@ STATIC mp_obj_t mp_builtin_print(size_t n_args, const mp_obj_t *pos_args, mp_map mp_arg_parse_all(0, NULL, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, u.args); #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES - // TODO file may not be a concrete object (eg it could be a small-int) + mp_get_stream_raise(u.args[ARG_file].u_obj, MP_STREAM_OP_WRITE); mp_print_t print = {MP_OBJ_TO_PTR(u.args[ARG_file].u_obj), mp_stream_write_adaptor}; #endif diff --git a/py/modsys.c b/py/modsys.c index 609f8b454c..98addfcfc0 100644 --- a/py/modsys.c +++ b/py/modsys.c @@ -106,7 +106,8 @@ STATIC mp_obj_t mp_sys_print_exception(size_t n_args, const mp_obj_t *args) { #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES void *stream_obj = &mp_sys_stdout_obj; if (n_args > 1) { - stream_obj = MP_OBJ_TO_PTR(args[1]); // XXX may fail + mp_get_stream_raise(args[1], MP_STREAM_OP_WRITE); + stream_obj = MP_OBJ_TO_PTR(args[1]); } mp_print_t print = {stream_obj, mp_stream_write_adaptor}; From b92a8adbfa54dc259554b435a81b6cec19cae99a Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 20 Jun 2018 16:08:25 +1000 Subject: [PATCH 818/828] tests: Add tests using "file" argument in print and sys.print_exception. --- tests/io/builtin_print_file.py | 17 +++++++++++++++++ tests/misc/print_exception.py | 9 +++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/io/builtin_print_file.py diff --git a/tests/io/builtin_print_file.py b/tests/io/builtin_print_file.py new file mode 100644 index 0000000000..d9b8e2a960 --- /dev/null +++ b/tests/io/builtin_print_file.py @@ -0,0 +1,17 @@ +# test builtin print function, using file= argument + +import sys + +try: + sys.stdout +except AttributeError: + print('SKIP') + raise SystemExit + +print(file=sys.stdout) +print('test', file=sys.stdout) + +try: + print(file=1) +except (AttributeError, OSError): # CPython and uPy differ in error message + print('Error') diff --git a/tests/misc/print_exception.py b/tests/misc/print_exception.py index 9ab8e728b9..f120fe1e18 100644 --- a/tests/misc/print_exception.py +++ b/tests/misc/print_exception.py @@ -56,3 +56,12 @@ try: f() except Exception as e: print_exc(e) + +# Test non-stream object passed as output object, only valid for uPy +if hasattr(sys, 'print_exception'): + try: + sys.print_exception(Exception, 1) + had_exception = False + except OSError: + had_exception = True + assert had_exception From 34344a413fb1939d476f43429a8a4e142f6fe3c0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 20 Jun 2018 16:26:12 +1000 Subject: [PATCH 819/828] py/stream: Remove stray empty line at start of file. This was accidentally added in 6abede2ca9e221b6aefcaccbda0c89e367507df1 --- py/stream.c | 1 - 1 file changed, 1 deletion(-) diff --git a/py/stream.c b/py/stream.c index b9932b35e8..448de41bbb 100644 --- a/py/stream.c +++ b/py/stream.c @@ -1,4 +1,3 @@ - /* * This file is part of the MicroPython project, http://micropython.org/ * From 7f41f73f0f81e0ecbdb37d32ea7ad8cbc7468b06 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 22 Jun 2018 15:07:01 +1000 Subject: [PATCH 820/828] stm32/qspi: Don't require data reads and writes to be a multiple of 4. Prior to this patch the QSPI driver assumed that the length of all data reads and writes was a multiple of 4. This patch allows any length. Reads are optimised for speed by using 32-bit transfers when possible, but writes always use a byte transfer because they only use a single data IO line and are relatively slow. --- ports/stm32/qspi.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/ports/stm32/qspi.c b/ports/stm32/qspi.c index 97f055c099..a7cbbde014 100644 --- a/ports/stm32/qspi.c +++ b/ports/stm32/qspi.c @@ -181,16 +181,12 @@ STATIC void qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, QUADSPI->AR = addr; - // Write out the data + // Write out the data 1 byte at a time while (len) { while (!(QUADSPI->SR & QUADSPI_SR_FTF)) { } - // TODO it seems that writes need to be 32-bit wide to start the xfer... - //*(volatile uint8_t*)QUADSPI->DR = *src++; - //--len; - QUADSPI->DR = *(uint32_t*)src; - src += 4; - len -= 4; + *(volatile uint8_t*)&QUADSPI->DR = *src++; + --len; } } @@ -253,13 +249,23 @@ STATIC void qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, QUADSPI->ABR = 0; // alternate byte: disable continuous read mode QUADSPI->AR = addr; // addres to read from - // Read in the data - while (len) { - while (!(QUADSPI->SR & QUADSPI_SR_FTF)) { + // Read in the data 4 bytes at a time if dest is aligned + if (((uintptr_t)dest & 3) == 0) { + while (len >= 4) { + while (!(QUADSPI->SR & QUADSPI_SR_FTF)) { + } + *(uint32_t*)dest = QUADSPI->DR; + dest += 4; + len -= 4; } - *(uint32_t*)dest = QUADSPI->DR; - dest += 4; - len -= 4; + } + + // Read in remaining data 1 byte at a time + while (len) { + while (!((QUADSPI->SR >> QUADSPI_SR_FLEVEL_Pos) & 0x3f)) { + } + *dest++ = *(volatile uint8_t*)&QUADSPI->DR; + --len; } QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag From ec7982ec6dc195a6b1381af2a18590414ef9e621 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 22 Jun 2018 15:30:34 +1000 Subject: [PATCH 821/828] stm32/mboot: Add support for erase/read/write of external SPI flash. This patch adds support to mboot for programming external SPI flash. It allows SPI flash to be programmed via a USB DFU utility in the same way that internal MCU flash is programmed. --- ports/stm32/mboot/README.md | 26 ++++++++ ports/stm32/mboot/main.c | 128 +++++++++++++++++++++++++++++------- 2 files changed, 130 insertions(+), 24 deletions(-) diff --git a/ports/stm32/mboot/README.md b/ports/stm32/mboot/README.md index 3486ebfb33..2ff6101b44 100644 --- a/ports/stm32/mboot/README.md +++ b/ports/stm32/mboot/README.md @@ -31,6 +31,32 @@ How to use #define MBOOT_BOOTPIN_PULL (MP_HAL_PIN_PULL_UP) #define MBOOT_BOOTPIN_ACTIVE (0) + Mboot supports programming external SPI flash via the DFU and I2C + interfaces. SPI flash will be mapped to an address range. To + configure it use the following options (edit as needed): + + #define MBOOT_SPIFLASH_ADDR (0x80000000) + #define MBOOT_SPIFLASH_BYTE_SIZE (2 * 1024 * 1024) + #define MBOOT_SPIFLASH_LAYOUT "/0x80000000/64*32Kg" + #define MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE (32 / 4) + #define MBOOT_SPIFLASH_SPIFLASH (&spi_bdev.spiflash) + #define MBOOT_SPIFLASH_CONFIG (&spiflash_config) + + This assumes that the board declares and defines the relevant SPI flash + configuration structs, eg in the board-specific bdev.c file. The + `MBOOT_SPIFLASH2_LAYOUT` string will be seen by the USB DFU utility and + must describe the SPI flash layout. Note that the number of pages in + this layout description (the `64` above) cannot be larger than 99 (it + must fit in two digits) so the reported page size (the `32Kg` above) + must be made large enough so the number of pages fits in two digits. + Alternatively the layout can specify multiple sections like + `32*16Kg,32*16Kg`, in which case `MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE` + must be changed to `16 / 4` to match tho `16Kg` value. + + Mboot supports up to two external SPI flash devices. To configure the + second one use the same configuration names as above but with + `SPIFLASH2`, ie `MBOOT_SPIFLASH2_ADDR` etc. + 2. Build the board's main application firmware as usual. 3. Build mboot via: diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c index 5e2e1819f6..11053971bc 100644 --- a/ports/stm32/mboot/main.c +++ b/ports/stm32/mboot/main.c @@ -81,7 +81,7 @@ static uint32_t get_le32(const uint8_t *b) { void mp_hal_delay_us(mp_uint_t usec) { // use a busy loop for the delay // sys freq is always a multiple of 2MHz, so division here won't lose precision - const uint32_t ucount = HAL_RCC_GetSysClockFreq() / 2000000 * usec / 2; + const uint32_t ucount = CORE_PLL_FREQ / 2000000 * usec / 2; for (uint32_t count = 0; ++count <= ucount;) { } } @@ -314,6 +314,14 @@ static int usrbtn_state(void) { /******************************************************************************/ // FLASH +#ifndef MBOOT_SPIFLASH_LAYOUT +#define MBOOT_SPIFLASH_LAYOUT "" +#endif + +#ifndef MBOOT_SPIFLASH2_LAYOUT +#define MBOOT_SPIFLASH2_LAYOUT "" +#endif + typedef struct { uint32_t base_address; uint32_t sector_size; @@ -332,7 +340,7 @@ typedef struct { || defined(STM32F732xx) \ || defined(STM32F733xx) -#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg" +#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT static const flash_layout_t flash_layout[] = { { 0x08000000, 0x04000, 4 }, @@ -350,7 +358,7 @@ static const flash_layout_t flash_layout[] = { #elif defined(STM32F767xx) -#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*032Kg,01*128Kg,07*256Kg" +#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*032Kg,01*128Kg,07*256Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT // This is for dual-bank mode disabled static const flash_layout_t flash_layout[] = { @@ -378,20 +386,18 @@ static uint32_t flash_get_sector_index(uint32_t addr) { return 0; } -static int do_mass_erase(void) { +static int flash_mass_erase(void) { // TODO return -1; } -static int do_page_erase(uint32_t addr) { +static int flash_page_erase(uint32_t addr) { uint32_t sector = flash_get_sector_index(addr); if (sector == 0) { // Don't allow to erase the sector with this bootloader in it return -1; } - led_state(LED0, 1); - HAL_FLASH_Unlock(); // Clear pending flags (if any) @@ -411,8 +417,6 @@ static int do_page_erase(uint32_t addr) { return -1; } - led_state(LED0, 0); - // Check the erase set bits to 1, at least for the first 256 bytes for (int i = 0; i < 64; ++i) { if (((volatile uint32_t*)addr)[i] != 0xffffffff) { @@ -423,15 +427,12 @@ static int do_page_erase(uint32_t addr) { return 0; } -static int do_write(uint32_t addr, const uint8_t *src8, size_t len) { +static int flash_write(uint32_t addr, const uint8_t *src8, size_t len) { if (addr >= flash_layout[0].base_address && addr < flash_layout[0].base_address + flash_layout[0].sector_size) { // Don't allow to write the sector with this bootloader in it return -1; } - static uint32_t led_tog = 0; - led_state(LED0, (led_tog++) & 16); - const uint32_t *src = (const uint32_t*)src8; size_t num_word32 = (len + 3) / 4; HAL_FLASH_Unlock(); @@ -449,6 +450,84 @@ static int do_write(uint32_t addr, const uint8_t *src8, size_t len) { return 0; } +/******************************************************************************/ +// Writable address space interface + +static int do_mass_erase(void) { + // TODO + return flash_mass_erase(); +} + +#if defined(MBOOT_SPIFLASH_ADDR) || defined(MBOOT_SPIFLASH2_ADDR) +static int spiflash_page_erase(mp_spiflash_t *spif, uint32_t addr, uint32_t n_blocks) { + for (int i = 0; i < n_blocks; ++i) { + int ret = mp_spiflash_erase_block(spif, addr); + if (ret != 0) { + return ret; + } + addr += MP_SPIFLASH_ERASE_BLOCK_SIZE; + } + return 0; +} +#endif + +static int do_page_erase(uint32_t addr) { + led_state(LED0, 1); + + #if defined(MBOOT_SPIFLASH_ADDR) + if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) { + return spiflash_page_erase(MBOOT_SPIFLASH_SPIFLASH, + addr - MBOOT_SPIFLASH_ADDR, MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE); + } + #endif + + #if defined(MBOOT_SPIFLASH2_ADDR) + if (MBOOT_SPIFLASH2_ADDR <= addr && addr < MBOOT_SPIFLASH2_ADDR + MBOOT_SPIFLASH2_BYTE_SIZE) { + return spiflash_page_erase(MBOOT_SPIFLASH2_SPIFLASH, + addr - MBOOT_SPIFLASH2_ADDR, MBOOT_SPIFLASH2_ERASE_BLOCKS_PER_PAGE); + } + #endif + + return flash_page_erase(addr); +} + +static void do_read(uint32_t addr, int len, uint8_t *buf) { + #if defined(MBOOT_SPIFLASH_ADDR) + if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) { + mp_spiflash_read(MBOOT_SPIFLASH_SPIFLASH, addr - MBOOT_SPIFLASH_ADDR, len, buf); + return; + } + #endif + #if defined(MBOOT_SPIFLASH2_ADDR) + if (MBOOT_SPIFLASH2_ADDR <= addr && addr < MBOOT_SPIFLASH2_ADDR + MBOOT_SPIFLASH2_BYTE_SIZE) { + mp_spiflash_read(MBOOT_SPIFLASH2_SPIFLASH, addr - MBOOT_SPIFLASH2_ADDR, len, buf); + return; + } + #endif + + // Other addresses, just read directly from memory + memcpy(buf, (void*)addr, len); +} + +static int do_write(uint32_t addr, const uint8_t *src8, size_t len) { + static uint32_t led_tog = 0; + led_state(LED0, (led_tog++) & 4); + + #if defined(MBOOT_SPIFLASH_ADDR) + if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) { + return mp_spiflash_write(MBOOT_SPIFLASH_SPIFLASH, addr - MBOOT_SPIFLASH_ADDR, len, src8); + } + #endif + + #if defined(MBOOT_SPIFLASH2_ADDR) + if (MBOOT_SPIFLASH2_ADDR <= addr && addr < MBOOT_SPIFLASH2_ADDR + MBOOT_SPIFLASH2_BYTE_SIZE) { + return mp_spiflash_write(MBOOT_SPIFLASH2_SPIFLASH, addr - MBOOT_SPIFLASH2_ADDR, len, src8); + } + #endif + + return flash_write(addr, src8, len); +} + /******************************************************************************/ // I2C slave interface @@ -554,7 +633,7 @@ void i2c_slave_process_rx_end(void) { if (len > I2C_CMD_BUF_LEN) { len = I2C_CMD_BUF_LEN; } - memcpy(buf, (void*)i2c_obj.cmd_rdaddr, len); + do_read(i2c_obj.cmd_rdaddr, len, buf); i2c_obj.cmd_rdaddr += len; } else if (buf[0] == I2C_CMD_WRITE) { if (i2c_obj.cmd_wraddr == APPLICATION_ADDR) { @@ -732,7 +811,8 @@ static int dfu_handle_tx(int cmd, int arg, int len, uint8_t *buf, int max_len) { if (cmd == DFU_UPLOAD) { if (arg >= 2) { dfu_state.cmd = DFU_CMD_UPLOAD; - memcpy(buf, (void*)((arg - 2) * max_len + dfu_state.addr), len); + uint32_t addr = (arg - 2) * max_len + dfu_state.addr; + do_read(addr, len, buf); return len; } } else if (cmd == DFU_GETSTATUS && len == 6) { @@ -773,14 +853,14 @@ enum { typedef struct _pyb_usbdd_obj_t { bool started; + bool tx_pending; USBD_HandleTypeDef hUSBDDevice; uint8_t bRequest; uint16_t wValue; uint16_t wLength; - uint8_t rx_buf[USB_XFER_SIZE]; - uint8_t tx_buf[USB_XFER_SIZE]; - bool tx_pending; + __ALIGN_BEGIN uint8_t rx_buf[USB_XFER_SIZE] __ALIGN_END; + __ALIGN_BEGIN uint8_t tx_buf[USB_XFER_SIZE] __ALIGN_END; // RAM to hold the current descriptors, which we configure on the fly __ALIGN_BEGIN uint8_t usbd_device_desc[USB_LEN_DEV_DESC] __ALIGN_END; @@ -1135,14 +1215,14 @@ enter_bootloader: __ASM volatile ("msr basepri_max, %0" : : "r" (pri) : "memory"); #endif - #if 0 - #if defined(MICROPY_HW_BDEV_IOCTL) - MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_INIT, 0); + #if defined(MBOOT_SPIFLASH_ADDR) + MBOOT_SPIFLASH_SPIFLASH->config = MBOOT_SPIFLASH_CONFIG; + mp_spiflash_init(MBOOT_SPIFLASH_SPIFLASH); #endif - #if defined(MICROPY_HW_BDEV2_IOCTL) - MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_INIT, 0); - #endif + #if defined(MBOOT_SPIFLASH2_ADDR) + MBOOT_SPIFLASH2_SPIFLASH->config = MBOOT_SPIFLASH2_CONFIG; + mp_spiflash_init(MBOOT_SPIFLASH2_SPIFLASH); #endif dfu_init(); From 92667dc2e57420a9960f80c80da7d3c49c8c7fd6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 22 Jun 2018 15:32:32 +1000 Subject: [PATCH 822/828] tools/pydfu.py: Add support for multiple memory segments. Segments are separated by / and begin with the memory address. This follows how the ST DFU tool works. --- tools/pydfu.py | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/tools/pydfu.py b/tools/pydfu.py index a33e497129..a7adda37cc 100755 --- a/tools/pydfu.py +++ b/tools/pydfu.py @@ -394,24 +394,25 @@ def get_memory_layout(device): intf = cfg[(0, 0)] mem_layout_str = get_string(device, intf.iInterface) mem_layout = mem_layout_str.split('/') - addr = int(mem_layout[1], 0) - segments = mem_layout[2].split(',') - seg_re = re.compile(r'(\d+)\*(\d+)(.)(.)') result = [] - for segment in segments: - seg_match = seg_re.match(segment) - num_pages = int(seg_match.groups()[0], 10) - page_size = int(seg_match.groups()[1], 10) - multiplier = seg_match.groups()[2] - if multiplier == 'K': - page_size *= 1024 - if multiplier == 'M': - page_size *= 1024 * 1024 - size = num_pages * page_size - last_addr = addr + size - 1 - result.append(named((addr, last_addr, size, num_pages, page_size), - "addr last_addr size num_pages page_size")) - addr += size + for mem_layout_index in range(1, len(mem_layout), 2): + addr = int(mem_layout[mem_layout_index], 0) + segments = mem_layout[mem_layout_index + 1].split(',') + seg_re = re.compile(r'(\d+)\*(\d+)(.)(.)') + for segment in segments: + seg_match = seg_re.match(segment) + num_pages = int(seg_match.groups()[0], 10) + page_size = int(seg_match.groups()[1], 10) + multiplier = seg_match.groups()[2] + if multiplier == 'K': + page_size *= 1024 + if multiplier == 'M': + page_size *= 1024 * 1024 + size = num_pages * page_size + last_addr = addr + size - 1 + result.append(named((addr, last_addr, size, num_pages, page_size), + "addr last_addr size num_pages page_size")) + addr += size return result From a2ac7e4fc9eab62bcba3056bcd651b7903770396 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 22 Jun 2018 15:39:10 +1000 Subject: [PATCH 823/828] stm32/boards: Add .ld and af.csv files for STM32F722. These files can also be used for F723, F732 and F733 MCUs. --- ports/stm32/boards/stm32f722.ld | 27 +++++ ports/stm32/boards/stm32f722_af.csv | 146 ++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 ports/stm32/boards/stm32f722.ld create mode 100644 ports/stm32/boards/stm32f722_af.csv diff --git a/ports/stm32/boards/stm32f722.ld b/ports/stm32/boards/stm32f722.ld new file mode 100644 index 0000000000..f2a1d85117 --- /dev/null +++ b/ports/stm32/boards/stm32f722.ld @@ -0,0 +1,27 @@ +/* + GNU linker script for STM32F722, STM32F723, STM32F732, STM32F733 +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 32K /* sectors 0,1 */ + FLASH_APP (rx) : ORIGIN = 0x08008000, LENGTH = 480K /* sectors 2-7 */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 256K /* DTCM+SRAM1+SRAM2 */ +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define tho top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x20038000; /* tunable */ diff --git a/ports/stm32/boards/stm32f722_af.csv b/ports/stm32/boards/stm32f722_af.csv new file mode 100644 index 0000000000..24500f5057 --- /dev/null +++ b/ports/stm32/boards/stm32f722_af.csv @@ -0,0 +1,146 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, +,,SYS,TIM1/2,TIM3/4/5,TIM8/9/10/11/LPTIM1,I2C1/2/3/USART1,SPI1/I2S1/SPI2/I2S2/SPI3/I2S3/SPI4/5,SPI2/I2S2/SPI3/I2S3/SPI3/I2S3/SAI1/UART4,SPI2/I2S2/SPI3/I2S3/USART1/2/3/UART5,SAI2/USART6/UART4/5/7/8/OTG1_FS,CAN1/TIM12/13/14/QUADSPI/FMC/OTG2_HS,SAI2/QUADSPI/SDMMC2/OTG2_HS/OTG1_FS,SDMMC2,UART7/FMC/SDMMC1/OTG2_FS,,,SYS,ADC +PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,SAI2_SD_B,,,,,EVENTOUT,ADC123_IN0 +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,,,,,EVENTOUT,ADC123_IN1 +PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,SAI2_SCK_B,,,,,,,EVENTOUT,ADC123_IN2 +PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,,,,,EVENTOUT,ADC123_IN3 +PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,,,EVENTOUT,ADC12_IN4 +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,,,OTG_HS_ULPI_CK,,,,,EVENTOUT,ADC12_IN5 +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,,,EVENTOUT,ADC12_IN6 +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SD,,,,TIM14_CH1,,,FMC_SDNWE,,,EVENTOUT,ADC12_IN7 +PortA,PA8,MCO1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,,EVENTOUT, +PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,,,,,,EVENTOUT, +PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,,,EVENTOUT, +PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,,EVENTOUT, +PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,,UART4_RTS,,,,,,,EVENTOUT, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,UART4_CTS,,OTG_HS_ULPI_D1,,,,,EVENTOUT,ADC12_IN8 +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,,OTG_HS_ULPI_D2,,,,,EVENTOUT,ADC12_IN9 +PortB,PB2,,,,,,,SAI1_SD_A,SPI3_MOSI/I2S3_SD,,QUADSPI_CLK,,,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,,,SDMMC2_D2,,,,,EVENTOUT, +PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,SPI2_NSS/I2S2_WS,,,SDMMC2_D3,,,,,EVENTOUT, +PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,,,OTG_HS_ULPI_D7,,FMC_SDCKE1,,,EVENTOUT, +PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,,QUADSPI_BK1_NCS,,FMC_SDNE1,,,EVENTOUT, +PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,FMC_NL,,,EVENTOUT, +PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,,,,CAN1_RX,SDMMC2_D4,,SDMMC1_D4,,,EVENTOUT, +PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,CAN1_TX,SDMMC2_D5,,SDMMC1_D5,,,EVENTOUT, +PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,,USART3_TX,,,OTG_HS_ULPI_D3,,,,,EVENTOUT, +PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,,USART3_RX,,,OTG_HS_ULPI_D4,,,,,EVENTOUT, +PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,,USART3_CK,,,OTG_HS_ULPI_D5,,OTG_HS_ID,,,EVENTOUT, +PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,,USART3_CTS,,,OTG_HS_ULPI_D6,,,,,EVENTOUT, +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,,SPI2_MISO,,USART3_RTS,,TIM12_CH1,SDMMC2_D0,,OTG_HS_DM,,,EVENTOUT, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,SDMMC2_D1,,OTG_HS_DP,,,EVENTOUT, +PortC,PC0,,,,,,,,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,,EVENTOUT,ADC123_IN10 +PortC,PC1,TRACED0,,,,,SPI2_MOSI/I2S2_SD,SAI1_SD_A,,,,,,,,,EVENTOUT,ADC123_IN11 +PortC,PC2,,,,,,SPI2_MISO,,,,,OTG_HS_ULPI_DIR,,FMC_SDNE0,,,EVENTOUT,ADC123_IN12 +PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,,FMC_SDCKE0,,,EVENTOUT,ADC123_IN13 +PortC,PC4,,,,,,I2S1_MCK,,,,,,,FMC_SDNE0,,,EVENTOUT,ADC12_IN14 +PortC,PC5,,,,,,,,,,,,,FMC_SDCKE0,,,EVENTOUT,ADC12_IN15 +PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,,USART6_TX,,SDMMC2_D6,,SDMMC1_D6,,,EVENTOUT, +PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,SDMMC2_D7,,SDMMC1_D7,,,EVENTOUT, +PortC,PC8,TRACED1,,TIM3_CH3,TIM8_CH3,,,,UART5_RTS,USART6_CK,,,,SDMMC1_D0,,,EVENTOUT, +PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,UART5_CTS,,QUADSPI_BK1_IO0,,,SDMMC1_D1,,,EVENTOUT, +PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,,,EVENTOUT, +PortC,PC11,,,,,,,SPI3_MISO,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,,,EVENTOUT, +PortC,PC12,TRACED3,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDMMC1_CK,,,EVENTOUT, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD0,,,,,,,,,,CAN1_RX,,,FMC_D2,,,EVENTOUT, +PortD,PD1,,,,,,,,,,CAN1_TX,,,FMC_D3,,,EVENTOUT, +PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,,,EVENTOUT, +PortD,PD3,,,,,,SPI2_SCK/I2S2_CK,,USART2_CTS,,,,,FMC_CLK,,,EVENTOUT, +PortD,PD4,,,,,,,,USART2_RTS,,,,,FMC_NOE,,,EVENTOUT, +PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT, +PortD,PD6,,,,,,SPI3_MOSI/I2S3_SD,SAI1_SD_A,USART2_RX,,,,SDMMC2_CK,FMC_NWAIT,,,EVENTOUT, +PortD,PD7,,,,,,,,USART2_CK,,,,SDMMC2_CMD,FMC_NE1,,,EVENTOUT, +PortD,PD8,,,,,,,,USART3_TX,,,,,FMC_D13,,,EVENTOUT, +PortD,PD9,,,,,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT, +PortD,PD10,,,,,,,,USART3_CK,,,,,FMC_D15,,,EVENTOUT, +PortD,PD11,,,,,,,,USART3_CTS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16/FMC_CLE,,,EVENTOUT, +PortD,PD12,,,TIM4_CH1,LPTIM1_IN1,,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17/FMC_ALE,,,EVENTOUT, +PortD,PD13,,,TIM4_CH2,LPTIM1_OUT,,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT, +PortD,PD14,,,TIM4_CH3,,,,,,UART8_CTS,,,,FMC_D0,,,EVENTOUT, +PortD,PD15,,,TIM4_CH4,,,,,,UART8_RTS,,,,FMC_D1,,,EVENTOUT, +PortE,PE0,,,TIM4_ETR,LPTIM1_ETR,,,,,UART8_RX,,SAI2_MCK_A,,FMC_NBL0,,,EVENTOUT, +PortE,PE1,,,,LPTIM1_IN2,,,,,UART8_TX,,,,FMC_NBL1,,,EVENTOUT, +PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,QUADSPI_BK1_IO2,,,FMC_A23,,,EVENTOUT, +PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT, +PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,,,FMC_A20,,,EVENTOUT, +PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,,,FMC_A21,,,EVENTOUT, +PortE,PE6,TRACED3,TIM1_BKIN2,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,SAI2_MCK_B,,FMC_A22,,,EVENTOUT, +PortE,PE7,,TIM1_ETR,,,,,,,UART7_RX,,QUADSPI_BK2_IO0,,FMC_D4,,,EVENTOUT, +PortE,PE8,,TIM1_CH1N,,,,,,,UART7_TX,,QUADSPI_BK2_IO1,,FMC_D5,,,EVENTOUT, +PortE,PE9,,TIM1_CH1,,,,,,,UART7_RTS,,QUADSPI_BK2_IO2,,FMC_D6,,,EVENTOUT, +PortE,PE10,,TIM1_CH2N,,,,,,,UART7_CTS,,QUADSPI_BK2_IO3,,FMC_D7,,,EVENTOUT, +PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,,,,,SAI2_SD_B,,FMC_D8,,,EVENTOUT, +PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,,,,,SAI2_SCK_B,,FMC_D9,,,EVENTOUT, +PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,,,,,SAI2_FS_B,,FMC_D10,,,EVENTOUT, +PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCK_B,,FMC_D11,,,EVENTOUT, +PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FMC_D12,,,EVENTOUT, +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT, +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT, +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT, +PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN9 +PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN14 +PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN15 +PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_RX,QUADSPI_BK1_IO3,,,,,,EVENTOUT,ADC3_IN4 +PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_TX,QUADSPI_BK1_IO2,,,,,,EVENTOUT,ADC3_IN5 +PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,UART7_RTS,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT,ADC3_IN6 +PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,UART7_CTS,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT,ADC3_IN7 +PortF,PF10,,,,,,,,,,,,,,,,EVENTOUT,ADC3_IN8 +PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,,,EVENTOUT, +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT, +PortF,PF13,,,,,,,,,,,,,FMC_A7,,,EVENTOUT, +PortF,PF14,,,,,,,,,,,,,FMC_A8,,,EVENTOUT, +PortF,PF15,,,,,,,,,,,,,FMC_A9,,,EVENTOUT, +PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT, +PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT, +PortG,PG2,,,,,,,,,,,,,FMC_A12,,,EVENTOUT, +PortG,PG3,,,,,,,,,,,,,FMC_A13,,,EVENTOUT, +PortG,PG4,,,,,,,,,,,,,FMC_A14/FMC_BA0,,,EVENTOUT, +PortG,PG5,,,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT, +PortG,PG6,,,,,,,,,,,,,,,,EVENTOUT, +PortG,PG7,,,,,,,,,USART6_CK,,,,FMC_INT,,,EVENTOUT, +PortG,PG8,,,,,,,,,USART6_RTS,,,,FMC_SDCLK,,,EVENTOUT, +PortG,PG9,,,,,,,,,USART6_RX,QUADSPI_BK2_IO2,SAI2_FS_B,SDMMC2_D0,FMC_NE2/FMC_NCE,,,EVENTOUT, +PortG,PG10,,,,,,,,,,,SAI2_SD_B,SDMMC2_D1,FMC_NE3,,,EVENTOUT, +PortG,PG11,,,,,,,,,,,SDMMC2_D2,,,,,EVENTOUT, +PortG,PG12,,,,LPTIM1_IN1,,,,,USART6_RTS,,,SDMMC2_D3,FMC_NE4,,,EVENTOUT, +PortG,PG13,TRACED0,,,LPTIM1_OUT,,,,,USART6_CTS,,,,FMC_A24,,,EVENTOUT, +PortG,PG14,TRACED1,,,LPTIM1_ETR,,,,,USART6_TX,QUADSPI_BK2_IO3,,,FMC_A25,,,EVENTOUT, +PortG,PG15,,,,,,,,,USART6_CTS,,,,FMC_SDNCAS,,,EVENTOUT, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH2,,,,LPTIM1_IN2,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,,FMC_SDCKE0,,,EVENTOUT, +PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,,FMC_SDNE0,,,EVENTOUT, +PortH,PH4,,,,,I2C2_SCL,,,,,,OTG_HS_ULPI_NXT,,,,,EVENTOUT, +PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT, +PortH,PH6,,,,,I2C2_SMBA,SPI5_SCK,,,,TIM12_CH1,,,FMC_SDNE1,,,EVENTOUT, +PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,,FMC_SDCKE1,,,EVENTOUT, +PortH,PH8,,,,,I2C3_SDA,,,,,,,,FMC_D16,,,EVENTOUT, +PortH,PH9,,,,,I2C3_SMBA,,,,,TIM12_CH2,,,FMC_D17,,,EVENTOUT, +PortH,PH10,,,TIM5_CH1,,,,,,,,,,FMC_D18,,,EVENTOUT, +PortH,PH11,,,TIM5_CH2,,,,,,,,,,FMC_D19,,,EVENTOUT, +PortH,PH12,,,TIM5_CH3,,,,,,,,,,FMC_D20,,,EVENTOUT, +PortH,PH13,,,,TIM8_CH1N,,,,,UART4_TX,CAN1_TX,,,FMC_D21,,,EVENTOUT, +PortH,PH14,,,,TIM8_CH2N,,,,,UART4_RX,CAN1_RX,,,FMC_D22,,,EVENTOUT, +PortH,PH15,,,,TIM8_CH3N,,,,,,,,,FMC_D23,,,EVENTOUT, +PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,,,,FMC_D24,,,EVENTOUT, +PortI,PI1,,,,TIM8_BKIN2,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,,,EVENTOUT, +PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,,,,,,,FMC_D26,,,EVENTOUT, +PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,FMC_D27,,,EVENTOUT, +PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCK_A,,FMC_NBL2,,,EVENTOUT, +PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,,,EVENTOUT, +PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,,,EVENTOUT, +PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,,,EVENTOUT, +PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI9,,,,,,,,,UART4_RX,CAN1_RX,,,FMC_D30,,,EVENTOUT, +PortI,PI10,,,,,,,,,,,,,FMC_D31,,,EVENTOUT, +PortI,PI11,,,,,,,,,,,OTG_HS_ULPI_DIR,,,,,EVENTOUT, +PortI,PI12,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI13,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI14,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI15,,,,,,,,,,,,,,,,EVENTOUT, From c14919792868d0e42bb84d61e584797c6c977114 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Jun 2018 13:54:03 +1000 Subject: [PATCH 824/828] py/compile: Combine break and continue compile functions. --- py/compile.c | 25 +++++++++++++------------ py/grammar.h | 4 ++-- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/py/compile.c b/py/compile.c index c62ed057dd..f242e74586 100644 --- a/py/compile.c +++ b/py/compile.c @@ -945,20 +945,21 @@ STATIC void compile_del_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { apply_to_single_or_list(comp, pns->nodes[0], PN_exprlist, c_del_stmt); } -STATIC void compile_break_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { - if (comp->break_label == INVALID_LABEL) { - compile_syntax_error(comp, (mp_parse_node_t)pns, "'break' outside loop"); +STATIC void compile_break_cont_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + uint16_t label; + const char *error_msg; + if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_break_stmt) { + label = comp->break_label; + error_msg = "'break' outside loop"; + } else { + label = comp->continue_label; + error_msg = "'continue' outside loop"; + } + if (label == INVALID_LABEL) { + compile_syntax_error(comp, (mp_parse_node_t)pns, error_msg); } assert(comp->cur_except_level >= comp->break_continue_except_level); - EMIT_ARG(unwind_jump, comp->break_label, comp->cur_except_level - comp->break_continue_except_level); -} - -STATIC void compile_continue_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { - if (comp->continue_label == INVALID_LABEL) { - compile_syntax_error(comp, (mp_parse_node_t)pns, "'continue' outside loop"); - } - assert(comp->cur_except_level >= comp->break_continue_except_level); - EMIT_ARG(unwind_jump, comp->continue_label, comp->cur_except_level - comp->break_continue_except_level); + EMIT_ARG(unwind_jump, label, comp->cur_except_level - comp->break_continue_except_level); } STATIC void compile_return_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { diff --git a/py/grammar.h b/py/grammar.h index 6abb1de8c0..ffedd2f8a7 100644 --- a/py/grammar.h +++ b/py/grammar.h @@ -122,8 +122,8 @@ DEF_RULE_NC(augassign, or(12), tok(DEL_PLUS_EQUAL), tok(DEL_MINUS_EQUAL), tok(DE DEF_RULE(del_stmt, c(del_stmt), and(2), tok(KW_DEL), rule(exprlist)) DEF_RULE(pass_stmt, c(generic_all_nodes), and(1), tok(KW_PASS)) DEF_RULE_NC(flow_stmt, or(5), rule(break_stmt), rule(continue_stmt), rule(return_stmt), rule(raise_stmt), rule(yield_stmt)) -DEF_RULE(break_stmt, c(break_stmt), and(1), tok(KW_BREAK)) -DEF_RULE(continue_stmt, c(continue_stmt), and(1), tok(KW_CONTINUE)) +DEF_RULE(break_stmt, c(break_cont_stmt), and(1), tok(KW_BREAK)) +DEF_RULE(continue_stmt, c(break_cont_stmt), and(1), tok(KW_CONTINUE)) DEF_RULE(return_stmt, c(return_stmt), and(2), tok(KW_RETURN), opt_rule(testlist)) DEF_RULE(yield_stmt, c(yield_stmt), and(1), rule(yield_expr)) DEF_RULE(raise_stmt, c(raise_stmt), and(2), tok(KW_RAISE), opt_rule(raise_stmt_arg)) From d23bec3fc89d1c1f7a2ac8023161e3f2620ffa13 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Jun 2018 13:57:55 +1000 Subject: [PATCH 825/828] py/compile: Combine subscript_2 and subscript_3 into one function. --- py/compile.c | 22 ++++++++++------------ py/grammar.h | 4 ++-- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/py/compile.c b/py/compile.c index f242e74586..a857598c52 100644 --- a/py/compile.c +++ b/py/compile.c @@ -2546,7 +2546,16 @@ STATIC void compile_trailer_period(compiler_t *comp, mp_parse_node_struct_t *pns } #if MICROPY_PY_BUILTINS_SLICE -STATIC void compile_subscript_3_helper(compiler_t *comp, mp_parse_node_struct_t *pns) { +STATIC void compile_subscript(compiler_t *comp, mp_parse_node_struct_t *pns) { + if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_2) { + compile_node(comp, pns->nodes[0]); // start of slice + assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should always be + pns = (mp_parse_node_struct_t*)pns->nodes[1]; + } else { + // pns is a PN_subscript_3, load None for start of slice + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); + } + assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_3); // should always be mp_parse_node_t pn = pns->nodes[0]; if (MP_PARSE_NODE_IS_NULL(pn)) { @@ -2590,17 +2599,6 @@ STATIC void compile_subscript_3_helper(compiler_t *comp, mp_parse_node_struct_t EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE); } } - -STATIC void compile_subscript_2(compiler_t *comp, mp_parse_node_struct_t *pns) { - compile_node(comp, pns->nodes[0]); // start of slice - assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should always be - compile_subscript_3_helper(comp, (mp_parse_node_struct_t*)pns->nodes[1]); -} - -STATIC void compile_subscript_3(compiler_t *comp, mp_parse_node_struct_t *pns) { - EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); - compile_subscript_3_helper(comp, pns); -} #endif // MICROPY_PY_BUILTINS_SLICE STATIC void compile_dictorsetmaker_item(compiler_t *comp, mp_parse_node_struct_t *pns) { diff --git a/py/grammar.h b/py/grammar.h index ffedd2f8a7..bd0a20876d 100644 --- a/py/grammar.h +++ b/py/grammar.h @@ -290,8 +290,8 @@ DEF_RULE(trailer_period, c(trailer_period), and(2), tok(DEL_PERIOD), tok(NAME)) #if MICROPY_PY_BUILTINS_SLICE DEF_RULE(subscriptlist, c(generic_tuple), list_with_end, rule(subscript), tok(DEL_COMMA)) DEF_RULE_NC(subscript, or(2), rule(subscript_3), rule(subscript_2)) -DEF_RULE(subscript_2, c(subscript_2), and_ident(2), rule(test), opt_rule(subscript_3)) -DEF_RULE(subscript_3, c(subscript_3), and(2), tok(DEL_COLON), opt_rule(subscript_3b)) +DEF_RULE(subscript_2, c(subscript), and_ident(2), rule(test), opt_rule(subscript_3)) +DEF_RULE(subscript_3, c(subscript), and(2), tok(DEL_COLON), opt_rule(subscript_3b)) DEF_RULE_NC(subscript_3b, or(2), rule(subscript_3c), rule(subscript_3d)) DEF_RULE_NC(subscript_3c, and(2), tok(DEL_COLON), opt_rule(test)) DEF_RULE_NC(subscript_3d, and_ident(2), rule(test), opt_rule(sliceop)) From 1a7109d65aa87596c7ce1824037fe298109962e9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Jun 2018 14:04:05 +1000 Subject: [PATCH 826/828] py/compile: Combine global and nonlocal statement compile functions. --- py/compile.c | 34 +++++++++++++++------------------- py/grammar.h | 4 ++-- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/py/compile.c b/py/compile.c index a857598c52..7e8ebfbab9 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1162,9 +1162,7 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) { } } -STATIC void compile_declare_global(compiler_t *comp, mp_parse_node_t pn, qstr qst) { - bool added; - id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qst, &added); +STATIC void compile_declare_global(compiler_t *comp, mp_parse_node_t pn, qstr qst, bool added, id_info_t *id_info) { if (!added && id_info->kind != ID_INFO_KIND_GLOBAL_EXPLICIT) { compile_syntax_error(comp, pn, "identifier redefined as global"); return; @@ -1178,19 +1176,7 @@ STATIC void compile_declare_global(compiler_t *comp, mp_parse_node_t pn, qstr qs } } -STATIC void compile_global_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { - if (comp->pass == MP_PASS_SCOPE) { - mp_parse_node_t *nodes; - int n = mp_parse_node_extract_list(&pns->nodes[0], PN_name_list, &nodes); - for (int i = 0; i < n; i++) { - compile_declare_global(comp, (mp_parse_node_t)pns, MP_PARSE_NODE_LEAF_ARG(nodes[i])); - } - } -} - -STATIC void compile_declare_nonlocal(compiler_t *comp, mp_parse_node_t pn, qstr qst) { - bool added; - id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qst, &added); +STATIC void compile_declare_nonlocal(compiler_t *comp, mp_parse_node_t pn, qstr qst, bool added, id_info_t *id_info) { if (added) { scope_find_local_and_close_over(comp->scope_cur, id_info, qst); if (id_info->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { @@ -1201,16 +1187,26 @@ STATIC void compile_declare_nonlocal(compiler_t *comp, mp_parse_node_t pn, qstr } } -STATIC void compile_nonlocal_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { +STATIC void compile_global_nonlocal_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { if (comp->pass == MP_PASS_SCOPE) { - if (comp->scope_cur->kind == SCOPE_MODULE) { + bool is_global = MP_PARSE_NODE_STRUCT_KIND(pns) == PN_global_stmt; + + if (!is_global && comp->scope_cur->kind == SCOPE_MODULE) { compile_syntax_error(comp, (mp_parse_node_t)pns, "can't declare nonlocal in outer code"); return; } + mp_parse_node_t *nodes; int n = mp_parse_node_extract_list(&pns->nodes[0], PN_name_list, &nodes); for (int i = 0; i < n; i++) { - compile_declare_nonlocal(comp, (mp_parse_node_t)pns, MP_PARSE_NODE_LEAF_ARG(nodes[i])); + qstr qst = MP_PARSE_NODE_LEAF_ARG(nodes[i]); + bool added; + id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qst, &added); + if (is_global) { + compile_declare_global(comp, (mp_parse_node_t)pns, qst, added, id_info); + } else { + compile_declare_nonlocal(comp, (mp_parse_node_t)pns, qst, added, id_info); + } } } } diff --git a/py/grammar.h b/py/grammar.h index bd0a20876d..50611bb9c4 100644 --- a/py/grammar.h +++ b/py/grammar.h @@ -157,8 +157,8 @@ DEF_RULE_NC(as_name, and_ident(2), tok(KW_AS), tok(NAME)) DEF_RULE_NC(import_as_names, list_with_end, rule(import_as_name), tok(DEL_COMMA)) DEF_RULE_NC(dotted_as_names, list, rule(dotted_as_name), tok(DEL_COMMA)) DEF_RULE_NC(dotted_name, list, tok(NAME), tok(DEL_PERIOD)) -DEF_RULE(global_stmt, c(global_stmt), and(2), tok(KW_GLOBAL), rule(name_list)) -DEF_RULE(nonlocal_stmt, c(nonlocal_stmt), and(2), tok(KW_NONLOCAL), rule(name_list)) +DEF_RULE(global_stmt, c(global_nonlocal_stmt), and(2), tok(KW_GLOBAL), rule(name_list)) +DEF_RULE(nonlocal_stmt, c(global_nonlocal_stmt), and(2), tok(KW_NONLOCAL), rule(name_list)) DEF_RULE_NC(name_list, list, tok(NAME), tok(DEL_COMMA)) DEF_RULE(assert_stmt, c(assert_stmt), and(3), tok(KW_ASSERT), rule(test), opt_rule(assert_stmt_extra)) DEF_RULE_NC(assert_stmt_extra, and_ident(2), tok(DEL_COMMA), rule(test)) From 36e474e83fa26cb78a9312dce5dc53a467c5d8b7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Jun 2018 14:10:29 +1000 Subject: [PATCH 827/828] py/compile: Combine or_test and and_test compile functions. --- py/compile.c | 11 ++--------- py/grammar.h | 4 ++-- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/py/compile.c b/py/compile.c index 7e8ebfbab9..032e0a6aec 100644 --- a/py/compile.c +++ b/py/compile.c @@ -2024,7 +2024,8 @@ STATIC void compile_lambdef(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_funcdef_lambdef(comp, this_scope, pns->nodes[0], PN_varargslist); } -STATIC void compile_or_and_test(compiler_t *comp, mp_parse_node_struct_t *pns, bool cond) { +STATIC void compile_or_and_test(compiler_t *comp, mp_parse_node_struct_t *pns) { + bool cond = MP_PARSE_NODE_STRUCT_KIND(pns) == PN_or_test; uint l_end = comp_next_label(comp); int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); for (int i = 0; i < n; i += 1) { @@ -2036,14 +2037,6 @@ STATIC void compile_or_and_test(compiler_t *comp, mp_parse_node_struct_t *pns, b EMIT_ARG(label_assign, l_end); } -STATIC void compile_or_test(compiler_t *comp, mp_parse_node_struct_t *pns) { - compile_or_and_test(comp, pns, true); -} - -STATIC void compile_and_test(compiler_t *comp, mp_parse_node_struct_t *pns) { - compile_or_and_test(comp, pns, false); -} - STATIC void compile_not_test_2(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_node(comp, pns->nodes[0]); EMIT_ARG(unary_op, MP_UNARY_OP_NOT); diff --git a/py/grammar.h b/py/grammar.h index 50611bb9c4..37b97a191c 100644 --- a/py/grammar.h +++ b/py/grammar.h @@ -231,8 +231,8 @@ DEF_RULE(lambdef_nocond, c(lambdef), and_blank(4), tok(KW_LAMBDA), opt_rule(vara // power: atom_expr ['**' factor] // atom_expr: 'await' atom trailer* | atom trailer* -DEF_RULE(or_test, c(or_test), list, rule(and_test), tok(KW_OR)) -DEF_RULE(and_test, c(and_test), list, rule(not_test), tok(KW_AND)) +DEF_RULE(or_test, c(or_and_test), list, rule(and_test), tok(KW_OR)) +DEF_RULE(and_test, c(or_and_test), list, rule(not_test), tok(KW_AND)) DEF_RULE_NC(not_test, or(2), rule(not_test_2), rule(comparison)) DEF_RULE(not_test_2, c(not_test_2), and(2), tok(KW_NOT), rule(not_test)) DEF_RULE(comparison, c(comparison), list, rule(expr), rule(comp_op)) From 25ae98f07cb3c4488cb955403dfe56b8bb8db6f0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Jun 2018 14:20:42 +1000 Subject: [PATCH 828/828] py/compile: Combine expr, xor_expr and and_expr into one function. This and the previous 4 commits combined have change in code size of: bare-arm: -92 minimal x86: -544 unix x64: -544 unix nanbox: -712 stm32: -116 cc3200: -128 esp8266: -348 esp32: -232 --- py/compile.c | 29 ++++++++++------------------- py/grammar.h | 6 +++--- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/py/compile.c b/py/compile.c index 032e0a6aec..7daf911035 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1985,15 +1985,6 @@ STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { } } -STATIC void c_binary_op(compiler_t *comp, mp_parse_node_struct_t *pns, mp_binary_op_t binary_op) { - int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); - compile_node(comp, pns->nodes[0]); - for (int i = 1; i < num_nodes; i += 1) { - compile_node(comp, pns->nodes[i]); - EMIT_ARG(binary_op, binary_op); - } -} - STATIC void compile_test_if_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_test_if_else)); mp_parse_node_struct_t *pns_test_if_else = (mp_parse_node_struct_t*)pns->nodes[1]; @@ -2102,16 +2093,16 @@ STATIC void compile_star_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_syntax_error(comp, (mp_parse_node_t)pns, "*x must be assignment target"); } -STATIC void compile_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { - c_binary_op(comp, pns, MP_BINARY_OP_OR); -} - -STATIC void compile_xor_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { - c_binary_op(comp, pns, MP_BINARY_OP_XOR); -} - -STATIC void compile_and_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { - c_binary_op(comp, pns, MP_BINARY_OP_AND); +STATIC void compile_binary_op(compiler_t *comp, mp_parse_node_struct_t *pns) { + MP_STATIC_ASSERT(MP_BINARY_OP_OR + PN_xor_expr - PN_expr == MP_BINARY_OP_XOR); + MP_STATIC_ASSERT(MP_BINARY_OP_OR + PN_and_expr - PN_expr == MP_BINARY_OP_AND); + mp_binary_op_t binary_op = MP_BINARY_OP_OR + MP_PARSE_NODE_STRUCT_KIND(pns) - PN_expr; + int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); + compile_node(comp, pns->nodes[0]); + for (int i = 1; i < num_nodes; ++i) { + compile_node(comp, pns->nodes[i]); + EMIT_ARG(binary_op, binary_op); + } } STATIC void compile_term(compiler_t *comp, mp_parse_node_struct_t *pns) { diff --git a/py/grammar.h b/py/grammar.h index 37b97a191c..5a5b682acc 100644 --- a/py/grammar.h +++ b/py/grammar.h @@ -241,9 +241,9 @@ DEF_RULE_NC(comp_op_not_in, and(2), tok(KW_NOT), tok(KW_IN)) DEF_RULE_NC(comp_op_is, and(2), tok(KW_IS), opt_rule(comp_op_is_not)) DEF_RULE_NC(comp_op_is_not, and(1), tok(KW_NOT)) DEF_RULE(star_expr, c(star_expr), and(2), tok(OP_STAR), rule(expr)) -DEF_RULE(expr, c(expr), list, rule(xor_expr), tok(OP_PIPE)) -DEF_RULE(xor_expr, c(xor_expr), list, rule(and_expr), tok(OP_CARET)) -DEF_RULE(and_expr, c(and_expr), list, rule(shift_expr), tok(OP_AMPERSAND)) +DEF_RULE(expr, c(binary_op), list, rule(xor_expr), tok(OP_PIPE)) +DEF_RULE(xor_expr, c(binary_op), list, rule(and_expr), tok(OP_CARET)) +DEF_RULE(and_expr, c(binary_op), list, rule(shift_expr), tok(OP_AMPERSAND)) DEF_RULE(shift_expr, c(term), list, rule(arith_expr), rule(shift_op)) DEF_RULE_NC(shift_op, or(2), tok(OP_DBL_LESS), tok(OP_DBL_MORE)) DEF_RULE(arith_expr, c(term), list, rule(term), rule(arith_op))